Практическое использование классов net framework для разработки «корпоративного


Содержание

«Хочу как Дуров»: пишем простой мессенджер

В последнее время растёт популярность приложений для обмена сообщениями. Пользователи предпочитают мессенджеры, потому что они позволяют взаимодействовать в режиме реального времени. В этой статье мы разберём процесс создания простого приложения для обмена мгновенными сообщениями. Не будем сильно углубляться в нюансы разработки: мы напишем рабочий мессенджер, который в дальнейшем можно будет улучшить.

Используемые технологии и инструменты

  1. Стек MEAN (Mongo, Express, Angular, Node).
  2. Сокеты для прямого обмена сообщениями.
  3. AJAX для регистрации и входа.

Подготовка

Структура будущего приложения выглядит примерно так:

Установите Node.js и MongoDB. Кроме того, нам понадобится библиотека AngularJS, скачайте её и скопируйте в папку lib каталога Client.

Чтобы сделать пользовательский интерфейс приложения привлекательнее, вы можете воспользоваться любой CSS-библиотекой. Скачайте её и скопируйте в lib .

Примечание: созданный мессенджер можно будет интегрировать в качестве виджета в любой проект.

Серверная часть

Шаг 1. Запуск проекта

Перейдите в каталог Server и выполните команду:

Она запустит новый проект.

Укажите все необходимые сведения. В результате будет создан файл package.json примерно следующего вида:

Шаг 2. Установка зависимостей

  • socket.io — JavaScript-библиотека, которая предоставляет двустороннюю связь клиента и сервера в режиме реального времени;
  • express — фреймворк Node.js, предоставляющий набор функций для разработки мобильных и веб-приложений. Позволяет отвечать на HTTP-запросы, используя промежуточное ПО, а также отображать HTML-страницы.

Выполнение этих команд установит необходимые зависимости и добавит их в package.json :

Выглядеть они будут примерно так:

Шаг 3. Создание сервера

Создадим сервер, который обслуживает порт 3000 и возвращает HTML-файл при вызове. Для инициализации нового соединения сокету нужно передать HTTP-объект. Событие connection будет прослушивать входящие сокеты, каждый сокет будет выпускать событие disconnect, которое будет вызвано при отключении клиента. Мы будем использовать следующие функции:

  • socket.on(. ) — ожидает событие, и когда оно происходит, то выполняет функцию обратного вызова.
  • io.emit(. ) — используется для отправки сообщения всем подключенным сокетам.

Создайте сервер с именем server.js . Он должен:

  • Выводить сообщение в консоль при подключении пользователя.
  • Слушать событие chat message и транслировать полученное сообщение на все подключенные сокеты.
  • Когда пользователь отключается, выводить сообщение в консоль.

В результате ваш сервер будет выглядеть примерно так:

Клиентская часть

Создайте файлы index.html в каталоге Client, style.css в каталоге CSS и app.js в каталоге js.

Client/index.html

Пусть это будет простой HTML-код, который получает и отображает наши сообщения.

14 ноября в 18:30, Витебск, беcплатно

Включите скрипты socket.io-client и angular.js в ваш HTML:

socket.io служит для нас клиентом. Он по умолчанию подключается к хосту, обслуживающему страницу.

В результате index.html должен выглядеть примерно так:

CSS/style.css

Чтобы придать нашей странице внешний вид окна чата, добавим немного стилей. Вы можете использовать любую CSS-библиотеку. Получим следующее:

js/app.js:

Создайте Angular-приложение и инициализируйте соединение сокета. Для этого нужны следующие функции:

  • socket.on(. ) — слушает определенное событие, и, когда оно происходит, выполняет функцию обратного вызова.
  • socket.emit(. ) — используется для отправки сообщения конкретному событию.

Теперь, когда будет набран текст сообщения и нажата кнопка, вызовите функцию отправки сообщения. Когда сокет получит сообщение, отобразите его.

В результате app.js будет выглядеть примерно так:

Запуск приложения

Перейдите в папку с server.js и запустите команду:

Сервер начнет работу на порте 3000. Чтобы в этом убедиться, перейдите по ссылке в браузере:

Ваш собственный мессенджер готов!

Что можно улучшить?


Можно создать базу данных для хранения информации о пользователях и истории сообщений. Лучше, если она будет масштабируемой, потому что в дальнейшем это позволит добавить больше функций.

Установите Mongoose или MongoDB для работы с базами данных Mongo:

Можете ознакомиться с документацией по их использованию: mongoose и mongodb.

Схема должна получиться примерно следующего вида:

Собеседникам могут быть присвоены следующие статусы:

  • Friend — собеседник является другом.
  • Pending — собеседник пока не принял запрос.
  • Blocked — собеседник заблокирован.

Предположим, что собеседник отклонил запрос на приватную беседу. В таком случае отправитель должен иметь возможность снова направить запрос.

Неплохо было бы реализовать для пользователя функционал сохранения сообщений в дополнительные коллекции. Пусть каждый её объект содержит сообщение, отправителя, получателя и время. Спроектируйте вашу базу данных в соответствии с конкретными потребностями и методами обработки сообщений.

Также вы можете создать REST API для обслуживания клиента. Например, конечную точку, отправляющую домашнюю страницу, из которой пользователи могут выполнять другие запросы.

Некоторые из возможных конечных точек API:

Вот какой мессенджер получился у автора статьи:

Внешний вид приложения

Исходный код приложения можно найти на GitHub.

Работа с данными в Entity Framework

Подключение и создание базы данных в Entity Framework Core

Entity Framework представляет прекрасное ORM-решение, которое позволяет автоматически связать обычные классы языка C# с таблицами в базе данных. Entity Framework Core нацелен в первую очередь на работу с СУБД MS SQL Server, однако поддерживает также и ряд других СУБД. В данном случае мы будем работать с базами данных в MS SQL Server.

Также стоит отметить, что здесь мы будем использовать именно Entity Framework Core 2.1 — кроссплатформенное решение на базе .NET Core, которое отличается от предыдущих версий, например, от Entity Framework 6. Более подробно с работой с Entity Framework Core можно ознакомиться в соответствуюшем руководстве.

Для работы с Entity Framework вначале создадим новый проект ASP.NET Core по шаблону Web Application (Model-View-Controller). Пусть он будет называться EFDataApp .

По умолчанию в проекте библиотеки Entity Framework отсутствуют, и их надо добавить. Это можно сделать разными способами — через Nuget, через Package Manager Console, либо просто вписав нужную зависимость в project.json. Выберем последний способ.

Для взаимодействия с MS SQL Server через Entity Framework необходим пакет Microsoft.EntityFrameworkCore.SqlServer . Но, кроме того, перед работой с базой данных нам предварительно надо создать эту базу данных в соответствии с вышеопределенными моделями. И для этого потребуется пакет Microsoft.EntityFrameworkCore.Tools . В проекте для версии ASP.NET Core 2.0 и выше эти пакеты уже присутствуют по умолчанию.

Далее добавим в проект новую папку, которую назовем Models. И в этой папке определим новый класс Phone:

Эта модель представляет те объекты, которые будут храниться в базе данных.

Чтобы взаимодействовать с базой данных через Entity Framework нам нужен контекст данных — класс, унаследованный от класса Microsoft.EntityFrameworkCore.DbContext . Поэтому добавим в папку Models новый класс, который назовем MobileContext:

Свойство DbSet представляет собой коллекцию объектов, которая сопоставляется с определенной таблицей в базе данных. При этом по умолчанию название свойства должно соответствовать множественному числу названию модели в соответствии с правилами английского языка. То есть phone — название класса модели представляет единственное число, а phones — множественное число.

Через параметр options в конструктор контекста данных будут передаваться настройки контекста.

В конструкторе с помощью вызова Database.EnsureCreated() по определению моделей будет создаваться база данных (если она отсутствует).

Чтобы подключаться к базе данных, нам надо задать параметры подключения. Для этого изменим файл appsettings.json , добавив в него определение строки подключения:

В данном случае мы будем использовать упрощенный движок базы данных LocalDB, который представляет легковесную версию SQL Server Express, предназначенную специально для разработки приложений.

И последним шагом в настройке проекта является изменение файла Startup.cs . В нем нам надо изменить метод ConfigureServices() :

Добавление контекста данных в виде сервиса позволит затем получать его в конструкторе контроллера через механизм внедрения зависимостей.

1. Net Framework – единый каркас среды разработки. Исполнительная среда clr. Понятие и функции среды разработки. Управляемый и неуправляемый код. Сборщик мусора.

2. Управляемый и неуправляемый код. .Net Framework: особенности разработки приложений с использованием библиотеки .Net Framework. Необходимость установки нескольких версий библиотеки.

3. Единство каркаса Framework .Net. Встроенные примитивные и структурные типы.

В каркасе Framework .Net можно выделить два основных компонента:

• статический — FCL (Framework Class Library) — библиотеку классов каркаса;

• динамический — CLR (Common Language Runtime) — общеязыковую исполнительную среду.

Каркас стал единым для всех языков среды. Поэтому, на каком бы языке программирования не велась разработка, она использует классы одной и той же библиотеки. Многие классы библиотеки, составляющие общее ядро, используются всеми языками. Отсюда единство интерфейса приложения, на каком бы языке оно не разрабатывалось, единство работы с коллекциями и другими контейнерами данных, единство связывания с различными хранилищами данных и прочая универсальность.

Важной частью библиотеки FCL стали классы, задающие примитивные типы — те типы, которые считаются встроенными в язык программирования. Типы каркаса покрывают все множество встроенных типов, встречающихся в языках программирования. Типы языка программирования проецируются на соответствующие типы каркаса. Тип, называемый в языке Visual Basic — Integer, а в языке C# — int, проецируется на один и тот же тип каркаса System.Int32.

Частью библиотеки стали не только простые встроенные типы, но и структурные типы, задающие организацию данных — строки, массивы, перечисления, структуры (записи).

Компиляторы языков программирования, включенные в Visual Studio .Net, создают модули на промежуточном языке MSIL (Microsoft Intermediate Language), называемом далее просто — IL. Фактически компиляторы создают так называемый управляемый модуль — переносимый исполняемый файл (Portable Executable или PE-файл). Этот файл содержит код на IL и метаданные — всю необходимую информацию как для CLR, так и конечных пользователей, работающих с приложением. О метаданных — важной новинке Framework .Net — мы еще будем говорить неоднократно. В зависимости от выбранного типа проекта, PE-файл может иметь уточнения exe, dll, mod или mdl.

Заметьте, PE-файл, имеющий уточнение exe, хотя и является exe-файлом, но это не совсем обычный, исполняемый Windows, файл. При его запуске он распознается как специальный PE-файл и передается CLR для обработки. Исполнительная среда начинает работать с кодом, в котором специфика исходного языка программирования исчезла. Код на IL начинает выполняться под управлением CLR (по этой причине код называется управляемым). Исполнительную среду можно рассматривать как своеобразную виртуальную IL-машину. Эта машина транслирует «на лету» требуемые для исполнения участки кода в команды реального процессора, который в действительности и выполняет код.

Еще одной важной особенностью построения CLR является то, что исполнительная среда берет на себя часть функций, традиционно входящих в ведение разработчиков трансляторов, и облегчает тем самым их работу. Один из таких наиболее значимых компонентов CLR — сборщик мусора (Garbage Collector). Под сборкой мусора понимается освобождение памяти, занятой объектами, которые стали бесполезными и не используются в дальнейшей работе приложения.

Основные компоненты .NET Framework (CLR и Framework Class Library)

Active member

В первой статье Вы узнали, что платформа .NET Framework состоит из 2 основных компонентов, это общеязыковая исполняющая среда (CLR) и библиотека классов платформы (FCL).

Сегодня мы более подробно рассмотрим, каждый из этих компонентов.
CLR

Ядром платформы .NET Framework является общеязыковая исполняющая среда (Common Language Runtime) или сокращенно CLR.

На компьютере храниться в виде файла динамической библиотеки mscoree.dll, в проекте данная сборка подключается автоматически.

В предыдущей статье мы научились создавать файл сборку. Данный файл содержит внутри себя управляемый код на промежуточном языке IL, который может выполняться только в среде CLR, которую предоставляет нам платформа .NET Framework.

Какие задачи решает CLR?

  1. Загрузка пользовательских сборок
  2. Управление памятью
  3. Работа с потоками
  4. Безопасность выполнения кода
  5. Очистка памяти (сборщик мусора)
  6. и многое другое

Стоит понимать, что версия среды и версия платформы могут отличаться, как показано на рисунке ниже.


На рисунке видно, что версии среды 3.0, 3.5 — не существует. Поэтому важно понимать, что версия платформы и версия среды — это разные вещи.

Кроме двух компонентов, которыми часто описывают всю платформу, существует ещё два не мало важных компонента, которые составляют основу платформы .NET
CTS

CTS (Common Type System) – система общих типов.

Это детальное описание (спецификация) всех типов данных и программных конструкций, поддерживаемых исполняющей средой.

В частности описываются такие моменты, как взаимодействие между типами и их представление в формате метаданных. А так же определяет способы объявления, использования и управления типами в среде CLR, а так же обеспечивает многоязыковую поддержку.

Важно знать то, что CTS предоставляет разработчикам 5 типов. О них я уже писал ранее, но повторюсь ещё раз.

Типы: класс, интерфейс, делегат, структура, перечисление. Каждый тип может содержать любое количество членов.

Какие задачи решает CTS?

  1. Обеспечивает многоязыковую поддержку
  2. ООП
  3. Описывает характеристики членов. Например: доступность: public, private, protected
  4. Определяет правила, которых нужно придерживаться языкам, чтобы типы и объекты написанные на разных языках мог бы взаимодействовать между собой

Ещё одним важным моментом, связанным с CTS, является, то, что она содержит набор фундаментальных типов данных.

И хотя в любом языке, у каждого типа свое ключевое слово, но стоит понимать, что все они в итоге соответствуют одному и тому же типу, который храниться в сборке mscorlib.dll.

Например: в CTS описан тип Int32, который храниться в библиотеки mscorlib.dll. И хотя в языке c# он будет иметь ключевое слово int, а допустим в Visual Basic — Integer. Все эти ключевые слова, всего лишь псевдонимы, к одному и тому же типу Int32.

И ещё важно понимать, что, не смотря на то, что для c# указано ключевое слово int, мы так же можем использовать и Int32.

// int a = 5;
// System.Int32 b = 10;
CLS

CLS (Common Language Specification), набор правил описывающих, как минимальный, так и полный набор функциональных возможностей, которые должен поддерживать каждый отдельный .NET-компилятор.

Напомню, что для каждого языка в мире .NET используется свой компилятор (csc.exe — c# , vbc.exe — Visual Basic), но, не смотря на то, что компилятор для каждого языка свой, в результате образуется промежуточный код, на языке IL.

Это необходимо для того, чтобы код, который получался после компиляции, мог бы обслуживаться средой CLR, а так же к нему могли бы получать доступ все языки платформы .NET Framework.

Как видно из описания, понимание CLS требуется в основном разработчикам компиляторов, рядовым разработчикам данная информация вряд ли пригодиться.

В итоге мы получаем примерно вот такую структуру:

На самом деле в .NET существует два типа библиотек:

    BCL (Base >Base Class Library (BCL)

Base Class Library (BCL) — это стандартная библиотека для всех языков платформы .NET, которая содержит набор пространств имен. Внутри которых содержится набор базовых типов, которые обеспечивают: файловый и консольный ввод-вывод, безопасность, XML, сетевой доступ, многопоточную обработку и многое другое.

Основной или главной сборкой данной библиотеки является файл динамической библиотеки — mscorlib.dll

Данная библиотека подключается автоматически во время создания проекта, так же стоит понимать, что существуют и другие файлы сборки базовых библиотек.
Framework Class Library (FCL)

Вторым типом библиотек платформы .NET Framework является библиотека классов платформы (FCL). Она является вторым основным компонентом платформы .NET, которая упрощают работу программиста, предоставляя ему, более расширенные библиотеки, такие как: ASP.NET, ADO.NET, Windows Forms, WPF.

В принципе можно сказать, что Framework Class Library включает в себя библиотеку базовых классов BCL, которая, по сути, является её ядром.

Тогда на вопрос, из каких основных компонентов состоит платформа .NET? Можно ответить так:

.NET Framework = CLR + FCL

Такую официальную формулировку так же приводят: MSDN, Wiki и многие другие авторы книг.

«The key components of the .NET Framework are the common language runtime (CLR) and the .NET Framework class library». MSDN

Но мы знаем, что FCL включает в себя библиотеки базовых классов. И правильнее формулировка должна звучать так:

.NET Framework = CLR + Libraries (FCL, BCL)
Но тут конечно можно долго спорить.

Обзор технологии NET Framework

Платформа .NET Framework — это один из компонентов системы Windows. Он позволяет создавать и использовать приложения нового поколения. Назначение платформы .NET Framework :

  • создание целостной объектно-ориентированной среды программирования допускающей различные варианты реализации: код может храниться и выполняться локально; выполняться локально, а распространяться через Интернет; или выполняться удаленно;
  • предоставление среды выполнения кода, в которой число конфликтов при развертывании программного обеспечения и управлении версиями будет сведено к минимуму;
  • обеспечение безопасности выполнения кода в среде — в том числе кода, созданного неизвестным разработчиком или разработчиком с частичным доверием;
  • предоставление среды выполнения кода, позволяющей устранить проблемы, связанные с производительностью сред на основе сценариев или интерпретации;
  • унификация работы разработчиков в совершенно разных приложениях: как в приложениях Windows, так и в веб-приложениях;
  • использование промышленных стандартов во всех областях обмена данными и, как следствие, обеспечения совместимости кода, созданного в .NET Framework, с другими программами.

Платформа .NET Framework состоит из двух основных компонентов: среды CLR и библиотеки классов .NET Framework. Среда CLR — это фундамент платформы .NET Framework. Это своеобразный агент, управляющий кодом во время его выполнения, предоставляющий ключевые службы, связанные с такими процессами, как управление памятью, потоками и удаленными операциями, а также обеспечивающий безопасность типов и другими способами контролирующий правильность кода, гарантируя безопасность и стабильность приложений. Понятие управления кодом является для среды основополагающим. Код, созданный для среды, называется управляемым. Любой другой код называется неуправляемым кодом. Библиотека классов, второй основной компонент платформы .NET Framework, является обширным объектно-ориентированным набором типов, которые можно использовать для разработки самых различных приложений — от классических приложений с интерфейсом командной строки или графическим интерфейсом пользователя до новейших приложений на базе технологий ASP.NET , например веб-форм и веб-служб XML.

Платформа .NET Framework может располагаться на неуправляемом компоненте, который загружает среду CLR в собственные процессы и инициирует выполнение управляемого кода — тем самым создавая среду приложений, в которой может выполняться как управляемый, так и неуправляемый код. Платформа .NET Framework сама предоставляет несколько хост-приложений и поддерживает хост-приложения сторонних разработчиков.

Рассмотрим, к примеру, следующую ситуацию: платформа ASP.NET предоставляет масштабируемую среду для управляемого кода на стороне сервера. ASP.NET непосредственно взаимодействует со средой, обеспечивая работу приложений ASP.NET и веб-служб XML (речь о них пойдет ниже).

Обозреватель Internet Explorer является примером неуправляемого приложения, в котором располагается среда (в виде расширения типа MIME). Размещение среды в обозревателе Internet Explorer позволяет встраивать управляемые компоненты и элементы управления Windows Forms в документы HTML. Такое размещение среды делает возможным использование управляемого мобильного кода (схожего с элементами управления Microsoft ActiveX), предоставляя при этом расширенные возможности, характерные исключительно для управляемого кода, к примеру выполнение при частичном доверии или изолированное хранение файлов.

На рисунке ниже показаны связи между средой CLR, библиотекой классов, приложениями и всей системой в целом. Он также дает представление о том, как управляемый код работает в более крупной архитектуре.

.Платформа .NET Framework в составе системы

В следующих разделах подробно рассматриваются основные компоненты и возможности платформы .NET Framework.

Среда CLR отвечает за управление памятью, работу потоков, выполнение кода, проверку безопасности кода, компиляцию и другие системные службы. Эти функции включены в управляемый код, выполняемый в среде CLR.

Управляемым компонентам присваиваются разные уровни доверия на основании ряда факторов, связанных с их происхождением (Интернет, корпоративная сеть, локальный компьютер). От уровня доверия зависит способность управляемого компонента осуществлять доступ к файлам, реестру и прочим важным функциям даже в пределах одного активного приложения.

Среда отвечает за управление доступом для кода. Например, пользователь может указать, что тот или иной исполняемый файл, встроенный в веб-страницу, может показывать анимацию или проигрывать мелодию, но не может осуществлять доступ к персональным данным пользователя, файловой системе или сети. Это позволяет максимально расширить возможности надежного программного обеспечения, развертываемого через Интернет.

Кроме того, среда обеспечивает стабильность кода за счет применения инфраструктуры, осуществляющей проверку кода и типов — так называемой системы общих типов CTS. Система CTS гарантирует наличие полного описания в каждом управляемом коде. Как у Майкрософт, так и у сторонних разработчиков есть различные компиляторы, создающие управляемый код по стандарту CTS. Такой код может потреблять другие управляемые типы и экземпляры, неизменно сохраняя правильность и безопасность типов.

Управляемая среда также помогает устранить многие распространенные проблемы, связанные с программным обеспечением. Например, структура объектов и ссылки на них в среде CLR обрабатываются автоматически и освоождаются, когда перестают использоваться. Такое автоматическое управление памятью позволяет устранить две ошибки, наиболее часто встречающиеся в приложениях: утечку памяти и недействительные ссылки.

Кроме всего прочего, среда CLR повышает эффективность разработки. Независимо от того, на каком языке программист пишет приложение, он в полной мере может использовать все функции среды CLR, библиотеку классов и компоненты, написанные другими разработчиками на других языках программирования. Если поставщик решит создать компилятор приложений для среды CLR, он вполне может это сделать. Подобный компилятор позволяет использовать функции платформы .NET Framework в коде, написанного на соответствующем языке, благодаря чему значительно упрощается процесс миграции готовых приложений.

Среда разрабатывалась для приложений нового поколения, однако она отлично поддерживает существующее программное обеспечение. Совместимость управляемого и неуправляемого кода позволяет разработчикам не отказываться от необходимых компонентов COM и библиотек DLL.

При разработке среды целью было повышение производительности. Хотя в среде CLR доступно множество стандартных служб, управляемый код никогда не бывает интерпретируемым. Функция, известная как JIT-компиляция, позволяет выполнять любой код на машинном языке той системы, на которой он запускается. В то же время, диспетчер памяти устраняет возможность ее фрагментации и корректирует размещение ссылок, за счет чего мы получаем дополнительное повышение производительности.

Наконец, среда может располагаться на высокопроизводительных серверных приложениях, таких как SQL Server 2008 и службы IIS. Такая инфраструктура позволяет использовать при создании бизнес-логики управляемый код, сохраняя при этом высокий уровень производительности, характерный для передовых производственных серверов, поддерживающих размещение среды.

Библиотека классов .NET Framework — это набор стандартных типов, тесно связанных со средой CLR. Библиотека классов является объектно-ориентированной. В ней содержатся типы, на основании которых ваш управляемый код может выводить нужные функции. Это не только обеспечивает простоту использования типов в .NET Framework, но и сокращает количество времени, необходимое для изучения новых возможностей платформы. Кроме того, компоненты сторонних разработчиков могут полностью интегрироваться в библиотеку классов .NET Framework.


К примеру, классы коллекций в .NET Framework позволяют реализовать ряд интерфейсов, которые затем вы можете использовать для создания собственных классов. Классы коллекций, которые вы создадите, будут тесно интегрированы в набор классов .NET Framework.

Поскольку библиотека классов является объектно-ориентированной, типы в .NET Framework позволяют выполнять ряд стандартных операций программирования: управление строками, сбор данных, подключение к базам данных, доступ к файлам. В библиотеке также есть типы, поддерживающие самые разнообразные специализированные ситуации, с которыми вы сталкиваетесь при разработке приложений. Платформу .NET Framework можно использовать для создания следующих приложений и служб:

  • консольных приложений;
  • приложений с графическим интерфейсом пользователя для системы Windows (Windows Forms);
  • приложений ASP.NET; .
  • мобильных приложений; .
  • Веб-служб XML;
  • служб Windows.

Например, классы Windows Forms — это обширный набор стандартных типов, значительно упрощающих разработку графического интерфейса под Windows. При создании веб-форм ASP.NET можно использовать классы Web Forms.

Клиентские приложения больше всего напоминают классические приложения для системы Windows. Это приложения, отображающие на экране компьютера окна или формы, позволяющие пользователю выполнять те или иные задачи. Клиентским приложением может быть текстовый редактор, электронная таблица, а также бизнес-приложения: средства ввода данных, создания отчетов и т. д. В клиентских приложениях обычно используются окна, меню, кнопки и другие элементы графического интерфейса. Очень часто они осуществляют доступ к локальным ресурсам, например к файловой системе, и периферийным устройствам, например к принтерам.

Другая разновидность клиентских приложений — это традиционные элементы управления ActiveX (теперь на смену им пришли элементы управления Windows Forms), развертываемые через Интернет в виде веб-страниц. Они мало чем отличаются от других клиентских приложений: работают как готовые приложения, осуществляют доступ к локальным ресурсам и имеют графический интерфейс.

Раньше такие приложения создавались либо с использованием C или C++ и классов Microsoft Foundation (MFC), либо при помощи среды быстрой разработки приложений, к примеру Microsoft Visual Basic . Платформа .NET Framework объединила в себе возможности этих продуктов, предоставив целостную среду разработки, в значительной степени упрощающую создание клиентских приложений.

Классы Windows Forms, имеющиеся в .NET Framework, предназначены для разработки графического интерфейса пользователя. Они упрощают создание командных окон, кнопок, меню, панелей инструментов и других графических элементов, обеспечивая гибкость, необходимую для удовлетворения меняющихся потребностей бизнеса.

Например, в .NET Framework есть ряд простых свойств, при помощи которых можно изменить атрибуты, определяющие внешний вид форм. В некоторых случаях система, в которой разрабатывается приложение, не позволяет менять эти атрибуты напрямую. Тогда платформа .NET Framework создает форму заново. Это лишь один пример того, как в платформе .NET Framework осуществляется интеграция интерфейса разработки, упрощается и систематизируется написание кода.

В отличие от элементов управления ActiveX элементы Windows Forms осуществляют доступ к компьютеру пользователя в режиме частичного доверия. Это означает, что бинарный или готовый код к одним ресурсам системы пользователя может иметь доступ (например к элементам графического интерфейса и части файлов), а к другим не может. Благодаря управлению доступом для кода многие приложения, которые раньше приходилось устанавливать в системе пользователя, теперь можно развертывать через Интернет. Приложение может выполнять функции локальной программы, но при этом работать в виде веб-страницы.

Серверные приложения в мире управляемого кода реализуются через хост-приложения. Среда CLR размещается на неуправляемом приложении, что позволяет вашему управляемому коду контролировать поведение сервера. При такой модели вы можете использовать все функции среды CLR и библиотеки классов, добиваясь высокой производительности и масштабируемости сервера.

На рисунке ниже показана основная схема сети и работа управляемого кода в различных серверных средах. Сервер, к примеру IIS или SQL Server, выполняет стандартные операции, а за логику приложения отвечает управляемый код.

Управляемый код на стороне сервера

ASP.NET является средой размещения, позволяющей разработчикам использовать .NET Framework для создания веб-приложений. Между тем, ASP.NET отвечает не только за размещение. Это полноценная архитектура для разработки веб-узлов и объектов, распространяемых через Интернет, с использованием управляемого кода. И веб-формы, и веб-службы XML используют IIS и ASP.NET в качестве механизма публикации для приложений. И те, и другие имеют набор вспомогательных классов в .NET Framework.

Веб-службы XML — это важный шаг вперед в области веб-технологий. Они представляют собой компоненты распределенных серверных приложений и напоминают обычные веб-узлы. В отличие от веб-приложений веб-службы XML не имеют пользовательского интерфейса и не предназначены для обозревателей, будь то Internet Explorer или Netscape Navigator. Веб-службы XML состоят из стандартных программных компонентов, созданных для использования в других приложениях: традиционных клиентских приложениях, веб-приложениях и даже в других веб-службах XML. Благодаря этому технология веб-служб XML значительно ускоряет разработку приложений и их развертывание в высокораспределенной среде Интернета.

Если вам доводилось работать с более ранними версиями технологии ASP, вы сразу же заметите усовершенствования, введенные в ASP.NET в веб-формах. Например, страницы веб-форм можно писать на любом языке, если он поддерживается платформой .NET Framework. Кроме того, код не обязан располагаться в одном файле с текстом HTTP (хотя это не запрещено). Страницы веб-форм выполняются на машинном языке, поскольку, как и любое другое управляемое приложение, они могут в полной мере использовать преимущества среды CLR. Неуправляемые страницы ASP, напротив, всегда пишутся в виде сценария и интерпретируются. Страницы ASP.NET работают быстрее, они более функциональны, их проще разрабатывать, чем неуправляемые страницы ASP, поскольку они взаимодействуют со средой, как и другие управляемые приложения.

В платформе .NET Framework также имеется набор классов и средств, помогающих при разработке и использовании веб-служб XML. Веб-службы XML создаются на основе стандартов: SOAP (протокол удаленного вызова процедур), XML (расширяемый формат данных), WSDL (язык описания веб-служб). Платформа .NET Framework опирается на те же стандарты, благодаря чему развиваются возможности взаимодействия с решениями сторонних разработчиков.

Например, средство WSDL, включенное в комплект .NET Framework SDK, способно запросить веб-службу XML, размещенную в Интернете, проанализировать WSDL-описание службы и создать исходный код на C# или Visual Basic, который можно использовать в приложении, которое станет клиентом данной веб-службы. Исходный код может создавать классы, производные от стандартных классов, включенных в библиотеку, которые будут обрабатывать все базовые связи при помощи анализа SOAP и XML. Библиотека классов позволяет использовать веб-службы XML напрямую, однако средство WSDL, впрочем как и другие средства, входящие в комплект SDK, упрощает разработку приложений в платформе .NET Framework.

Если вы создаете и размещаете собственную службу XML, вы можете использовать набор классов .NET Framework, согласующихся со всеми стандартами, такими как SOAP, WSDL и XML. Их применение позволит вам сосредоточиться на логике службы и не тратить время на инфраструктуру связей, необходимую для распределенных приложений.

И наконец, как и страницы веб-форм в управляемой среде, веб-службы XML работают с высокой скоростью — со скоростью приложений на машинном языке — и используют масштабируемую систему связей IIS.

Собеседование по Java EE — Spring Framework (вопросы и ответы). Часть 1

Вопросы и ответы на собеседование по теме Spring Framework. Часть 1.

к списку вопросов раздела JEE

Вопросы

1. Расскажите о Spring Framework.
2. Каковы некоторые из важных особенностей и преимуществ Spring Framework?
3. Что вы понимаете под Dependency Injection (DI)?
4. Как реализуется DI в Spring Framework?
5. Каковы преимущества использования Spring Tool Suite?
6. Приведите названия некоторых важных Spring модулей.
7. Что вы понимаете под аспектно-ориентированным программированием (Aspect Oriented Programming — AOP)?
8. Что такое Aspect, Advice, Pointcut, JointPoint и Advice Arguments в АОП?
9. В чем разница между Spring AOP и AspectJ АОП?
10. Что такое IoC контейнер Spring?
11. Что такое Spring бин?
12. Какое значение имеет конфигурационный файл Spring Bean?
13. Каковы различные способы настроить класс как Spring Bean?
14. Какие вы знаете различные scope у Spring Bean?
15. Что такое жизненный цикл Spring Bean?
16. Как получить объекты ServletContext и ServletConfig внутри Spring Bean?
17. Что такое связывание в Spring и расскажите об аннотации @Autowired?
18. Каковы различные типы автоматического связывания в Spring?
19. Является ли Spring бин потокобезопасным?
20. Что такое контроллер в Spring MVC?
21. Какая разница между аннотациями @Component, @Repository и @Service в Spring?
22. Расскажите, что вы знаете о DispatcherServlet и ContextLoaderListener.
23. Что такое ViewResolver в Spring?
24. Что такое MultipartResolver и когда его использовать?
25. Как обрабатывать исключения в Spring MVC Framework?
26. Как создать ApplicationContext в программе Java?
27. Можем ли мы иметь несколько файлов конфигурации Spring?
28. Каковы минимальные настройки, чтобы создать приложение Spring MVC?
29. Как бы вы связали Spring MVC Framework и архитектуру MVC?
30. Как добиться локализации в приложениях Spring MVC?

31. Как мы можем использовать Spring для создания веб-службы RESTful, возвращающей JSON?
32. Приведите пример часто используемых аннотаций Spring.
33. Можем ли мы послать объект как ответ метода обработчика контроллера?
34. Как загрузить файл в Spring MVC?
35. Как проверить (валидировать) данные формы в Spring Web MVC Framework?
36. Что вы знаете Spring MVC Interceptor и как он используется?
37. Spring JdbcTemplate класс и его применение.
38. Как использовать Tomcat JNDI DataSource в веб-приложении Spring?
39. Каким образом можно управлять транзакциями в Spring?
40. Расскажите о Spring DAO.
41. Как интегрировать Spring и Hibernate?
42. Расскажите о Spring Security.
43. Как внедрить java.util.Properties в Spring Bean?
44. Назовите некоторые из шаблонов проектирования, используемых в Spring Framework?
45. Best Practices в Spring Framework.

Ответы

1. Расскажите о Spring Framework.

Spring Framework (или коротко Spring) — универсальный фреймворк с открытым исходным кодом для Java-платформы. Несмотря на то, что Spring Framework не обеспечивает какую-либо конкретную модель программирования, он стал широко распространённым в Java-сообществе главным образом как альтернатива и замена модели Enterprise JavaBeans. Spring Framework предоставляет бо́льшую свободу Java-разработчикам в проектировании; кроме того, он предоставляет хорошо документированные и лёгкие в использовании средства решения проблем, возникающих при создании приложений корпоративного масштаба. Обычно Spring описывают как облегченную платформу для построения Java-приложений, но с этим утверждением связаны два интересных момента. Во-первых, Spring можно использовать для построения любого приложения на языке Java (т.е. автономных, веб приложений, приложений JEE и т.д.), что отличает Spring от многих других платформ, таких как Apache Struts, которая ограничена только веб-приложениями. Во-вторых, характеристика “облегченная” в действительности не имеет никакого отношения к количеству классов или размеру дистрибутива; напротив, она определяет принцип всей философии Spring — минимальное воздействие. Платформа Spring является облегченной в том смысле, что для использования ядра Spring вы должны вносить минимальные (если вообще какие-либо) изменения в код своего приложения, а если в какой-то момент вы решите больше не пользоваться Spring, то и это сделать очень просто. Обратите внимание, что речь идет только о ядре Spring — многие дополнительные компоненты Spring, такие как доступ к
данным, требуют более тесной привязки к Spring Framework.

2. Каковы некоторые из важных особенностей и преимуществ Spring Framework?

Spring Framework обеспечивает решения многих задач, с которыми сталкиваются Java-разработчики и организации, которые хотят создать информационную систему, основанную на платформе Java. Из-за широкой функциональности трудно определить наиболее значимые структурные элементы, из которых он состоит. Spring Framework не всецело связан с платформой Java Enterprise, несмотря на его масштабную интеграцию с ней, что является важной причиной его популярности.

Spring Framework, вероятно, наиболее известен как источник расширений (features), нужных для эффективной разработки сложных бизнес-приложений вне тяжеловесных программных моделей, которые исторически были доминирующими в промышленности. Ещё одно его достоинство в том, что он ввел ранее неиспользуемые функциональные возможности в сегодняшние господствующие методы разработки, даже вне платформы Java. Этот фреймворк предлагает последовательную модель и делает её применимой к большинству типов приложений, которые уже созданы на основе платформы Java. Считается, что Spring Framework реализует модель разработки, основанную на лучших стандартах индустрии, и делает её доступной во многих областях Java. Таким образом к достоинствам Spring можно отнести:

  • Относительная легкость в изучении и применении фреймворка в разработке и поддержке приложения.
  • Внедрение зависимостей (DI) и инверсия управления (IoC) позволяют писать независимые друг от друга компоненты, что дает преимущества в командной разработке, переносимости модулей и т.д..
  • Spring IoC контейнер управляет жизненным циклом Spring Bean и настраивается наподобие JNDI lookup (поиска).
  • Проект Spring содержит в себе множество подпроектов, которые затрагивают важные части создания софта, такие как вебсервисы, веб программирование, работа с базами данных, загрузка файлов, обработка ошибок и многое другое. Всё это настраивается в едином формате и упрощает поддержку приложения.

3. Что вы понимаете под Dependency Injection (DI)?

Внедрение зависимости (Dependency injection, DI) — процесс предоставления внешней зависимости программному компоненту. Является специфичной формой «инверсии управления» ( Inversion of control, IoC), когда она применяется к управлению зависимостями. В полном соответствии с принципом единой обязанности объект отдаёт заботу о построении требуемых ему зависимостей внешнему, специально предназначенному для этого общему механизму. К достоинствам применения DI можно отнести:

  • Сокращение объема связующего кода. Одним из самых больших плюсов DI является возможность значительного сокращения объема кода, который должен быть написан для связывания вместе различных компонентов приложения. Зачастую этот код очень прост — при создании зависимости должен создаваться новый экземпляр соответствующего объекта.
  • Упрощенная конфигурация приложения. За счет применения DI процесс конфигурирования приложения значительно упрощается. Для конфигурирования классов, которые могут быть внедрены в другие классы, можно использовать аннотации или XML-файлы.
  • Возможность управления общими зависимостями в единственном репозитории. При традиционном подходе к управлению зависимостями в общих службах, к которым относятся, например, подключение к источнику данных, транзакция, удаленные службы и т.п., вы создаете экземпляры (или получаете их из определенных фабричных классов) зависимостей там, где они нужны — внутри зависимого класса. Это приводит к распространению зависимостей по множеству классов в приложении, что может затруднить их изменение. В случае использования DI вся информация об общих зависимостях содержится в единственном репозитории (в Spring есть возможность хранить эту информацию в XML-файлах или Java классах), что существенно упрощает управление зависимостями и снижает количество возможных ошибок.
  • Улучшенная возможность тестирования. Когда классы проектируются для DI, становится возможной простая замена зависимостей. Это особенно полезно при тестировании приложения.
  • Стимулирование качественных проектных решений для приложений. Вообще говоря, проектирование для DI означает проектирование с использованием интерфейсов. Используя Spring, вы получаете в свое распоряжение целый ряд средств DI и можете сосредоточиться на построении логики приложения, а не на поддерживающей DI платформе.

4. Как реализуется DI в Spring Framework?

Реализация DI в Spring основана на двух ключевых концепциях Java — компонентах JavaBean и интерфейсах. При использовании Spring в качестве поставщика DI вы получаете гибкость определения конфигурации зависимостей внутри своих приложений разнообразными путями (т.е. внешне в XML-файлах, с помощью конфигурационных Java классов Spring или посредством аннотаций Java в коде). Компоненты JavaBean (также называемые POJO (Plain Old Java Object — простой старый объект Java)) предоставляют стандартный механизм для создания ресурсов Java, которые являются конфигурируемыми множеством способов. За счет применения DI объем кода, который необходим при проектировании приложения на основе интерфейсов, снижается почти до нуля. Кроме того, с помощью интерфейсов можно получить максимальную отдачу от DI, потому что бины могут использовать любую реализацию интерфейса для удовлетворения их зависимости.

К типам реализации внедрения зависимостей в Spring относят:

Constructor Dependency Injection — это тип внедрения зависимостей, при котором зависимости компонента предоставляются ему в его конструкторе (или конструкторах).

Практическое использование классов net framework для разработки «корпоративного мессенджера»

В документации .NET Framework, в справочных разделах библиотеки классов .NET Framework, приводятся примеры кода. Кроме того, эта документация содержит подразделы с образцами кода, в которых демонстрируется выполнение определенных задач (разделы «Практическое руководство»). В нескольких технологических разделах содержатся также подразделы с образцами кода, последовательно описывающие набор связанных задач, выполнение которых необходимо в рамках общего сценария (разделы «Пошаговое руководство»).

Данный каталог позволяет быстро найти образцы кода для любой области технологий.

Повышение эффективности работы за счет использования Adaptive Access Layers и Dependency Injection

Продукты и технологии:

Adaptive Access Layers, Windows Communication Foundation, SQL Server, Dependency Injection, Windows Services

В статье рассматриваются:

  • цели разработки Adaptive Access Layers (AAL);
  • интеграция AAL с Dependency Injection;
  • реализация AAL;
  • отчеты и проверки;
  • преимущества использования AAL.

Одна из труднейших задач при управлении и разработке исходного кода сложного корпоративного решения — обеспечить, чтобы кодовая база оставалась целостной, интуитивно понятной, максимально тестируемой и в то же время поддающейся сопровождению и расширению несколькими группами в рамках большого отдела разработки ПО. Основная проблема в том, что разработчики обычно следуют набору правил и руководств, а также используют некий набор библиотек, что со временем приводит к укрупнению и усложнению их решений. Это вызвано тем, что они стремятся к созданию идеальной и интуитивно понятной реализации бизнес-логики, но подгоняют ее под правила и фиксированные API. В принципе, это влечет за собой больше работы, больше ошибок, меньше стандартизации, меньше повторного использования и падение общей эффективности труда и качества кода.


Я старший разработчик в ведущем онлайновом инвестиционном банке и сам наблюдал, как эти проблемы могут ограничивать эффективность работы. Эта статья является практическим примером, который отражает то, как наша группа разработки проанализировала и преодолела эти трудные проблемы за счет инновационного применения в период выполнения генерации кода и встраивания зависимостей (Dependency Injection, DI). Возможно, вы не согласитесь с некоторыми из проектировочных решений, выбранных нашей группой, но я уверен, что вы не станете спорить с тем, что они представляют новый и эффективный способ устранения ряда распространенных проблем в архитектуре ПО.

В моей компании имеется большой отдел внутренних разработок ПО (работающий на двух континентах), который постоянно поддерживает и расширяет нашу огромную кодовую базу для Microsoft .NET Framework. Эта кодовая база сконцентрирована на ряде критически важных для бизнеса Windows-служб, которые образуют высокопроизводительную и имеющую низкую латентность торговую систему, размещенную в наших информационных центрах. У нас есть несколько групп, отвечающих за платформу (кодовую базу и исполняющую среду), плюс множество групп, занимающихся проектами, которые непрерывно (и параллельно) совершенствуют и расширяют эту систему.

Я работал в группах платформы в течение нескольких лет и на себе прочувствовал недостатки несогласованной и чрезмерно сложной кодовой базы при многочисленных ревизиях платформы и оказании технической поддержки. Два года назад мы решили заняться этим вопросом, и я нашел следующие проблемы.

  • У нас было слишком много решений одних и тех же фундаментальных проблем. Хороший пример тому — большинство наших Windows-служб собственным уникальным способом комбинировали различные API в простой сервис с должной поддержкой протоколирования, трассировки, доступа к базе данных и т. д.
  • Наши реализации бизнес-логики были либо простыми (но не поддающимися модульному тестированию, слишком наивными и не соответствующими руководствам), либо чрезмерно сложными из-за большого объема инфраструктурного кода. Распространенный пример: простой код, который работал напрямую с .NET SQL Server API, и сложный код, содержащий гораздо больше строк тривиального инфраструктурного кода для поддержки автоматических повторных попыток выполнения операций, кеширования и прочего, чем в самой бизнес-логике.
  • У нас были вспомогательные библиотеки, поддерживающие большинство наших архитектурных принципов и правил кодирования, но они были реализованы в нескольких разных стилях и развивались независимо. Поэтому даже при их использовании так, как это диктовали правила, каждое решение получалось в итоге слишком объемным из-за большого количества сборок, на которое оно ссылалось, и весьма уязвимым перед изменениями в API. Это в свою очередь сильно усложняло введение новой функции в производственную среду, а также затрудняло обновление вспомогательных библиотек.
  • Общий набор применяемых правил и руководств и используемых вспомогательных библиотек был настолько велик, что лишь самые опытные из наших разработчиков могли в полной мере разобраться в них; барьер вхождения для новых разработчиков был крайне высок. Это означало, что была написана уйма нестандартного кода, который позднее либо отбрасывался, либо попадал в производственную среду и лишь увеличивал степень несогласованности.
  • В нескольких из наших базовых Windows-служб были централизованные «точки регистрации», где все группы, отвечающие за проекты, должны были модифицировать один и тот же код, например очень большое выражение switch, распределяющее команды или задания. Из-за этого слияние такого кода с основным превращалось в нетривиальную задачу.

Естественно, эти проблемы не были для нас чем-то новым или уникальным, и ряд общеизвестных проектировочных шаблонов описывает, как устранять подобные проблемы.

  • Шаблон фасада скрывает все детали обращения к сложному ресурсу за простым интерфейсом уровня доступа. Это способствует созданию четких и тестируемых реализаций бизнес-логики, где внешние ресурсы при тестировании можно легко имитировать.
  • DI, или контейнеры Inversion of Control (IoC), обеспечивают слабую связанность компонентов и тем самым облегчают их расширение, сопровождение и комбинирование. Эта методика также упрощает имитацию выбранных компонентов и тем самым увеличивает тестируемость.
  • Тщательно спроектированные API вспомогательных библиотек не заставляют изменять использующий их код; вместо этого они поддерживают интуитивно понятную реализацию.

Мы давно знали об этих шаблонах и применяли их в различных формах в рамках нашей кодовой базы. Но несколько фундаментальных проблем значительно ограничивало успешное использование этих шаблонов. Во-первых, шаблон фасада не исключает необходимость в большом количестве инфраструктурного кода — он просто перемещает его в другой класс и, в целом, просто создает больше работы для разработчика. Во-вторых, если только DI-контейнер не распознает автоматически свои компоненты в период выполнения (например, через атрибуты), он по-прежнему требует централизованной регистрации и на практике лишь вводит в реализацию дополнительный уровень. Наконец, проектировать и реализовать API, которые одновременно и гибки, и интуитивно понятны, и полезны, — задача дорогостоящая и крайне трудная.

Основная особенность методики AAL в том, что с ее помощью мы получаем общее централизованное место для реализации наших наиболее эффективных правил и принципов, не загрязняя код бизнес-логики.

Зачем мы создали Adaptive Access Layers

После нескольких сеансов мозгового штурма мы пришли к единому гибкому и эффективному решению всех этих проблем. Основная идея в том, чтобы скрыть все API за помечаемыми атрибутами интерфейсами уровня доступа и создать механизм реализации, способный реализовать такие интерфейсы в период выполнения в соответствии со всеми правилами и руководствами. Мы называем эту методику «Adaptive Access Layers» (AAL), поскольку в каждом решении с высокой степенью гибкости определяются необходимые ему интерфейсы уровня доступа. Мы объединили механизм реализации AAL с управляемым атрибутами DI-контейнером Autofac с открытым исходным кодом и добились создания гибкой инфраструктуры Windows-служб, которая резко упрощает создание четких, интуитивно понятных и тестируемых реализаций. Рис. 1 иллюстрирует, насколько резко уменьшается размер и сложность решения, когда для отделения реализации базовой логики ото всех сопутствующих библиотек и API используется AAL. Более светлые элементы на схеме представляют размеры одного решения, реализованного с помощью AAL (слева) и без этой методики (справа).

Рис. 1. Adaptive Access Layers (слева) кардинально упрощают решение и уменьшают его размеры

Database API Database API
Adaptive Access Layers Adaptive Access Layers
Solution Is Pure Business Logic Решение является чистой бизнес-логикой
Message Bus API Message Bus API
WCF Service Clients Клиенты WCF-сервисов
Logging API API протоколирования
Solution Is Big and Complex Решение является большим и сложным
Business Logic Бизнес-логика

Основная особенность методики AAL в том, что с ее помощью мы получаем общее централизованное место для реализации наших наиболее эффективных правил и принципов, не загрязняя код бизнес-логики. В этом отношении AAL похожа на аспектно-ориентированное программирование (aspect-oriented programming, AOP), а также на различные методики средств перехвата и прокси. Главное отличие в том, что AAL скрывает нижележащие API от кода бизнес-логики, тогда как другие методики раскрывают их и тем самым значительно увеличивают размеры решения.

Чтобы проиллюстрировать эту идею, я рассмотрю простой уровень доступа, размещаемый между некоей бизнес-логикой и стандартным журналом событий Windows. Для примера возьмем сервис, который регистрирует поступающие заказы в какой-то базе данных. Если вызов базы данных завершается неудачей, сервис должен записать ошибку в журнал событий.

При традиционном подходе это могло бы потребовать вызова .NET-метода EventLog.WriteEntry и выглядело бы как код на рис. 2. Данный подход не оптимален по двум причинам. Во-первых, он не слишком хорошо подходит для модульного тестирования, так как тесту пришлось бы анализировать журнал событий на компьютере, выполняющем модульные тесты для проверки того, что в этот журнал действительно записан элемент с правильным текстом. А во-вторых, четыре строки инфраструктурного кода «загрязняют» базовую часть бизнес-логики.

Рис. 2. Традиционное обращение к журналу событий

Обе проблемы устраняются введением интерфейса AAL между бизнес-логикой и нижележащим классом EventLog. Такой уровень демонстрируется в следующем коде:

Этот уровень определяется использующим атрибуты интерфейсом IOrderServiceEventLog, который реализуется через динамический класс механизмом реализации в период выполнения. Сам интерфейс имеет атрибут [EventLogContract], чтобы механизм реализации мог распознать его как уровень доступа к журналу событий. Единственный параметр — имя целевого журнала событий. Никаких ограничений на имя интерфейса или количество методов в нем нет. Каждый метод должен возвращать void (при записи информации в журнал событий просто нечего возвращать) и иметь атрибут [EventEntryContract]. Этот атрибут принимает все фиксированные входные метаданные (идентификатор, уровень серьезности и форматирование) как параметры, поэтому такие метаданные больше не нужно размещать в бизнес-логике.

При использовании интерфейса уровня доступа бизнес-логика с рис. 2 становится гораздо компактнее и понятнее:

Метод RegisterOrder в примере теперь прост, отлично читаем и гораздо более тестируемый, поскольку проверка больше не требует анализа журнала событий — вместо это используется небольшой класс-заглушка, реализующий интерфейс уровня доступа. Другое преимущество в том, что интерфейс IOrderServiceEventLog может инкапсулировать все взаимодействие сервиса заказов с журналом событий и тем самым давать простое, но полное представление того, какие элементы этого журнала пишет система.

(Примечание Недавно выпущенный Semantic Logging Application Block [SLAB] для использования поверх нового класса EventSource из .NET 4.5 охватывает те же идеи перемещения метаданных из кода в атрибуты и предоставления настраиваемых, строго типизированных методов протоколирования вместо нескольких универсальных методов. Чтобы задействовать SLAB, разработчики должны реализовать собственный класс, производный от EventSource, и использовать его во всей кодовой базе. Я считаю, что наш подход ничуть не уступает SLAB, но легче в применении, так как требует от разработчиков лишь определения интерфейса, а не реализации класса. Главная особенность класса EventSource в том, что он поддерживает структурированное протоколирование событий через конфигурируемый набор приемников (sinks). Наша реализация уровня доступа в настоящее время не поддерживает такое протоколирование, но может быть легко расширена с этой целью, поскольку у нее есть доступ к структурированной информации через параметры метода нашего интерфейса.)

Доступ к базе данных — главная часть большинства корпоративных систем, и наши системы не являются исключением.

Я еще не рассматривал тело метода RegisterOrder, а именно вызов некоторых хранимых процедур в базе данных SQL Server, чтобы сохранить заказ для последующей обработки. Если бы моя группа реализовала это через .NET SqlClient API, нам понадобилось бы минимум 10 строк тривиального кода для создания экземпляров SqlConnection и SqlCommand, заполнения команды параметрами из свойств Order, выполнения команды и считывания набора результатов. Если бы мы попытались соблюсти дополнительные требования вроде автоматических повторных попыток на случай сбоев базы данных или истечения периодов ожидания, то легко могли бы получить 15–20 строк кода только для того, чтобы выполнить довольно простой вызов. И все это потребовалось бы только потому, что мишень вызова находится в хранимой процедуре, а не во внутрипроцессном .NET-методе. С точки зрения бизнес-логики, нет абсолютно никаких причин для того, чтобы наша реализация была такой громоздкой и сложной лишь из-за обработки между двумя системами.

Введя адаптивный уровень доступа к базе данных, аналогичный уровню доступа к журналу событий, можно реализовать тело упомянутого выше метода так, чтобы оно было простым и тестируемым:

До сих пор я иллюстрировал идеи, гибкость и мощь AAL. Теперь перейдем к более подробному рассмотрению уровней доступа, которые мы разработали и находим очень полезными. Я начну с только что упомянутого уровня доступа к базе данных.

Уровни доступа к базам данных Доступ к базе данных — главная часть большинства корпоративных систем, и наши системы не являются исключением. Будучи ключевым участником серьезной онлайновой торговли финансовыми инструментами, мы должны соответствовать некоторым строгим требованиям к безопасности и производительности, предъявляемым нашими клиентами и финансовыми органами, а значит, вынуждены тщательно защищать наши базы данных. В принципе, мы обращаемся к базам данных только через хранимые процедуры, так как они позволяют нам применять детализированные правила безопасности и проверять все запросы к базам данных на предмет производительности и нагрузки на сервер до того, как они попадут в наши производственные системы.

Мы тщательно оценили, способны ли такие средства объектно-реляционного сопоставления (ORM), как Entity Framework, помочь нам в создании более простого и тестируемого кода без отказа от хранимых процедур. Мы пришли к заключению, что Entity Framework — крайне привлекательное решение, но слишком сильно зависимое от возможности композиции и исполнения сложных SQL-выражений в период выполнения. Эта инфраструктура может сопоставлять хранимые процедуры, но, когда сопоставление ограничивается только хранимыми процедурами, она теряет большинство своих преимуществ. По этой причине мы решили реализовать свою инфраструктуру доступа к базам данных в виде адаптивного уровня доступа.

Наша реализация поддерживает вызовы хранимых процедур, операции выборки представлений и эффективные операции массовой вставки через функциональность массового копирования в SQL Server. Она позволяет сопоставлять входные данные напрямую из свойств DTO-класса (Data Transfer Objects) с параметрами хранимой процедуры и может аналогичным образом сопоставлять поля набора результатов со свойствами класса. Это способствует четкости синтаксиса при обращении к базе данных из .NET-кода.

Следующий код показывает простой уровень, который подходит для примера сервиса регистрации заказов:

Этот код сопоставляет одну хранимую процедуру и преобразует одну строку из набора результатов в экземпляр OrderConfirmation, инициализируемый на основе полей набора результатов. Параметрам сопоставленной хранимой процедуры присваиваются значения из свойств данного экземпляра Order. Эта функциональность сопоставления определена в атрибуте [StoredProcedureContract] и поэтому больше не требуется в реализации бизнес-логики, повышая ее четкость и читаемость.

Наша реализация поддерживает вызовы хранимых процедур, операции выборки представлений и эффективные операции массовой вставки через функциональность массового копирования в SQL Server.

Мы реализовали в уровне доступа к базе данных некоторые весьма продвинутые средства, так как пришли к выводу, что это простой и эффективный способ предлагать стандартную функциональность нашим разработчикам, не ограничивая им свободу в реализации своей бизнес-логики наиболее естественным и интуитивно понятным образом.

Одна из поддерживаемых функций — возможность массовой вставки строк через SQL-функциональность массового копирования. Она позволяет нашим разработчикам определять простой метод, который принимает перечисляемый набор DTO-класса, представляющий строки, вставляемые как входные данные. Уровень доступа управляет всеми деталями и тем самым избавляет бизнес-логику от 15–20 строк сложного кода, связанного с операциями над базой данных. Эта поддержка массового копирования — отличный пример концептуально простой операции (эффективной вставки строк в таблицу), которую в итоге обычно становится весьма сложно реализовать только потому, что нижележащий .NET-класс SqlBulkCopy работает с IDataReader, а не напрямую с нашим DTO-классом.

Уровень доступа к базе данных был первым из реализованных нами, и результат с самого начала оказался очень успешным. Благодаря этому мы пишем меньше кода (причем сам код стал проще), а наши решения естественным образом в максимальной мере охватываются модульными тестами. Отталкиваясь от этих положительных результатов, мы быстро осознали преимущества введения AAL между кодом бизнес-логики и несколькими другими внешними ресурсами.

Уровни доступа к сервисам Наша реализация торговой системы в высшей степени ориентирована на сервисы, и поэтому для нас важно отказоустойчивое взаимодействие между сервисами. Наш стандартный протокол — Windows Communication Foundation (WCF), и у нас много кода, связанного с WCF-вызовами.

Большинство реализаций следует одному и тому же шаблону в целом. Сначала разрешаются адреса конечных точек (как правило, наши сервисы работают либо в режиме «активный-активный», либо в режиме «активный-пассивный»). Затем с помощью .NET-класса ChannelFactory создается реализация класса канала, по которому вызывается нужный метод. Если метод выполняется успешно, канал закрывается и удаляется, но, если метод дает сбой, требуется проверка на исключение. В некоторых случаях имеет смысл повторно вызвать метод в той же конечной точке, тогда как в других ситуациях лучше выполнять автоматическое восстановление после сбоев и пытаться обращаться по одной из других доступных конечных точек. Вдобавок нам зачастую нужно помещать в карантин сбойную конечную точку на короткий период, чтобы не перегружать ее попытками соединения и вызовами метода, который дает ошибку.

Корректно реализовать этот шаблон — задача далеко не тривиальная, и она может потребовать 10–15 строк кода. И вновь это усложнение вводится только потому, что бизнес-логика, к которой нам нужно обращаться, находится в другом сервисе или вне основного процесса. Мы реализовали адаптивный уровень доступа к сервисам, чтобы исключить это усложнение и сделать вызов удаленного метода настолько же простым и безопасным, как и вызов внутрипроцессного метода.

Принципы и рабочий процесс идентичны таковым в уровне доступа к базам данных. Разработчик пишет помечаемый атрибутами интерфейсом, который сопоставляет только нужные методы, и наш механизм реализации создает тип периода выполнения, реализующий интерфейс с поведением, указанным в атрибутах.

Следующий код показывает небольшой уровень доступа к сервису, сопоставляющий единственный метод:

Атрибут интерфейса определяет нижележащий интерфейс с атрибутом [ServiceContract] (используется при внутреннем вызове ChannelFactory), применяемый протокол и идентификатор вызываемого сервиса. Последний служит ключом для нашей службы поиска сервисов (service locator), которая разрешает реальные адреса конечных точек во время вызова. Уровень доступа по умолчанию использует исходную WCF-привязку для данного протокола, но это можно изменить, задав дополнительные свойства в атрибуте [ServiceAccessLayer].

Единственный обязательный параметр в ServiceOperationContract — это «глагол действия», который идентифицирует сопоставленный метод в нижележащем контракте WCF-сервиса. Другие, необязательные параметры этого атрибута указывают, будут ли кешироваться результаты вызова сервиса и всегда ли безопасно автоматически восстанавливать операцию после неудачи, даже если вызов первой конечной точки WCF дал ошибку после того, как код был уже выполнен в целевом сервисе.

Другие уровни доступа Мы также создали аналогичные AAL для файлов трассировки, счетчиков производительности и своей шины сообщений. Все они основаны на тех же принципах, которые были проиллюстрированы в предыдущих примерах, т. е. бизнес-логика выражает доступ к ресурсам в максимально простом виде, перемещая все метаданные в атрибуты.

Интеграция встраивания зависимостей

С помощью уровней доступа нашим разработчикам больше не нужно реализовать массу тривиального инфраструктурного кода, но по-прежнему должен быть способ вызова механизма реализации AAL для получения экземпляра типа, реализуемого в период выполнения, при каждом вызове сопоставленного внешнего ресурса. Механизм реализации можно вызывать напрямую, но это идет вразрез с нашими принципами сохранения четкости и тестируемости бизнес-логики.

Мы решили эту проблему, зарегистрировав наш механизм реализации как источник динамической регистрации в Autofac, чтобы он вызывался всякий раз, когда Autofac не может разрешить какую-либо зависимость с помощью любой статической регистрации. В этом случае Autofac будет запрашивать механизм реализации, может ли тот разрешить данную комбинацию типа и идентификатора. Механизм проверит тип и предоставит его экземпляр, если этот тип является интерфейсом уровня доступа с атрибутами.

После этого мы сформировали среду, где реализации бизнес-логики могут просто объявлять свои типы интерфейсов уровня доступа и принимать их в качестве параметров (например, в конструкторах классов), а затем довериться DI-контейнеру в том, что он сумеет разрешить эти параметры, вызывая на внутреннем уровне механизм реализации. Такие реализации будут естественным образом работать с интерфейсами и будут легко тестируемыми, так как для тестирования этих интерфейсов достаточно создать несколько классов-заглушек.

Реализация

Все наши уровни доступа реализуются по одной методике. Общая идея заключается в том, чтобы реализовать всю функциональность в коде на чистом C# в абстрактном базовом классе, а потом лишь генерировать тонкий класс, который наследует от этого базового класса и реализует интерфейс. Сгенерированное тело каждого метода интерфейса просто делегирует выполнение универсальному методу Execute в базовом классе.

Сигнатура этого универсального метода выглядит так:

Первый параметр — атрибут метода интерфейса уровня доступа, из которого вызывается метод Execute. Как правило, он содержит все метаданные (например, имя хранимой процедуры, спецификацию повторных попыток и др.), необходимые методу Execute для того, чтобы обеспечить правильное поведение исполняющей среды.

Второй параметр — это отражаемый экземпляр MethodInfo для метода интерфейса. Он хранит всю информацию о реализуемом методе, в том числе типы и имена его параметров, и используется методом Execute для интерпретации третьего параметра, который содержит значения всех параметров для текущего вызова метода интерфейса. Метод Execute обычно пересылает эти значения нижележащему API ресурса, например в виде параметров для хранимой процедуры.


Четвертый параметр является пользовательским типом, который хранит фиксированные данные, используемые при каждом вызове метода, чтобы сделать его максимально эффективным. Фиксированные данные инициализируются только раз (методом абстрактного базового класса), когда механизм реализует класс периода выполнения. Наши уровни доступа к базам данных используют этот функционал для разового анализа хранимых процедур и подготовки шаблона SqlCommand к использованию при вызове метода.

Параметры Attribute и MethodInfo, передаваемые методу Execute, также отражаются только раз и повторно используются при каждом вызове метода, чтобы минимизировать издержки вызова.

Значение, возвращаемое Execute, используется как возвращаемое значение для реализованного метода интерфейса.

Эта структура довольно проста и, как оказалось, весьма гибка и эффективна. Мы повторно использовали ее во всех наших уровнях доступа через абстрактный общий базовый класс AccessLayerBase. Он реализует всю необходимую логику для анализа помеченного атрибутом интерфейса и управления процессом генерации нового класса в период выполнения. В каждой категории уровней доступа имеется свой специализированный абстрактный базовый класс, производный от AccessLayerBase. Он содержит реализацию доступа к внешнему ресурсу, например к хранимой процедуре в соответствии со всеми нашими правилами. На рис. 3 показана иерархия классов реализации для примера интерфейса уровня доступа к базе данных. Светло-серой рамкой обведены элементы инфраструктуры AAL, черной — интерфейс с атрибутом, определенный функциональным решением для бизнес-логики, а темно-серым — класс периода выполнения, генерируемый механизмом реализации AAL.

Рис. 3. Схема реализации уровня доступа

AccessLayerBase Abstract Class Абстрактный класс AccessLayerBase
DatabaseAccessLayer Class Класс DatabaseAccessLayer
IAccessLayer Interface Интерфейс IAccessLayer
далее все переводится по аналогии

Рис. 3 также иллюстрирует, как мы дали возможность базовым классам реализовать открытые интерфейсы (наследуя от IAccessLayer), которые предоставляют ключевую информацию о поведении. Это предназначено для использования не в реализациях бизнес-логики, а инфраструктурной логикой, например для отслеживания каждого неудачного вызова хранимой процедуры.

Эти интерфейсы уровня доступа также полезны в нескольких особых случаях, где технические или бизнес-требования вынуждают обращаться к нижележащему за уровнем доступа ресурсу таким способом, который не полностью поддерживается AAL. С помощью этих интерфейсов наши разработчики могут использовать AAL, но перехватывать и настраивать нижележащие операции так, чтобы они отвечали специфическим требованиям. Хороший пример — событие IDatabaseAccessLayer.ExecutingCommand. Оно генерируется непосредственно перед выполнением SqlCommand и позволяет нам настраивать этот объект, изменяя такие свойства, как значения интервалов ожидания или какие-то параметры.

Отчеты и проверки

AAL-интерфейсы с атрибутами в бизнес-логике также позволяют нам использовать механизм отражения применительно к компилируемым двоичным файлам на этапе сборки и получать полезные отчеты. Наша группа включила этот функционал в процесс сборки на основе Team Foundation Server (TFS), чтобы в результат каждой сборки теперь входило несколько небольших, но информативных XML-файлов.

Отчеты на этапе сборки Уровень доступа к базе данных сообщает полный список хранимых процедур, представлений и массовых операций вставок. На основе этого мы упрощаем анализ и проверяем, чтобы все необходимые объекты базы данных были должным образом развернуты и сконфигурированы до выпуска бизнес-логики.

Аналогично наш уровень доступа к журналу событий сообщает полный список элементов в этом журнале, которые может генерировать сервис. На стадиях после сборки эта информация принимается и преобразуется в пакет управления (management pack) для производственной среды Microsoft System Center Operations Manager. Это разумно, так как гарантирует, что у Operations Manager всегда будет актуальная информация о том, как лучше всего обрабатывать проблемы, возникающие в производственной среде.

Разумеется, широко используемая и очень гибкая платформа может стать единой точкой сбоя.

Автоматизированные пакеты Microsoft Installer Мы применили ту же методику отражения для сбора ценного ввода в пакеты Microsoft Installer (MSI), которые генерируются для наших Windows-служб на конечном этапе сборок в TFS. Главная цель этих пакетов — установить и сконфигурировать журнал событий и счетчики производительности, чтобы они гарантированно соответствовали развертываемой бизнес-логике. Процесс сборки извлекает имена для журнала событий и определения счетчиков производительности из двоичных файлов и автоматически генерирует MSI-пакет, устанавливающий эти имена и определения.

Проверки в период выполнения Одна из наиболее часто сообщаемых ошибок в нашей производственной среде — попытка сервиса вызвать несуществующую хранимую процедуру (или существующую, но с другой сигнатурой) из производственной базы данных. Такого рода ошибки случаются из-за того, что мы временами пропускаем развертывание всех необходимых объектов базы данных при развертывании сервиса в производственной среде. Здесь критически важно не то, что мы что-то упускаем при развертывании — это можно было бы сравнительно легко исправлять, а тот факт, что ошибки происходят не при развертывании, а позднее, при первом вызове хранимой процедуры. Мы использовали формируемый на основе отражения список всех объектов базы данных, к которым запрашивается доступ, и, чтобы устранить проблему, позволили нашим сервисам проверять наличие и корректность всех объектов при их запуске. Сервис просто проходит по списку объектов, а затем запрашивает каждый из них в базе данных для проверки того, что при необходимости он сможет обратиться к этому объекту. Тем самым мы переместили выявление всех таких ошибок на этап развертывания, когда исправить их гораздо проще и безопаснее.

Я перечислил эти дополнительные области применения, чтобы проиллюстрировать важнейшее преимущество AAL. Располагая почти полной информацией о поведении сервиса, доступной через отражение, мы открыли совершенно новое измерение интеллектуальной отчетности, сборки, автоматизации и мониторинга. Некоторые из открывшихся возможностей наша группа уже использует, но мы присматриваемся к ряду дополнительных интересных сфер применения.

Эффективность труда и качество

AAL, спроектированные и реализованные за последние два года, на практике доказали свою чрезвычайную пользу для повышения эффективности труда разработчиков и качества решений. Мы сократили время на подготовку нового сервиса с недель до часов, а на расширение существующих сервисов — с дней до минут. Это позволило увеличить нашу гибкость и тем самым удешевить стоимость собственных разработок.

Наши уровни доступа подходят при реализации огромного множества бизнес-решений. Однако несколько особых случаев, где эти уровни не годятся, все же есть: обычно это ситуации, в которых нужна очень высокая степень адаптации, например, когда имя вызываемой хранимой процедуры считывается из таблицы конфигурации и на этапе компиляции не известно. Наша группа умышленно предпочла не поддерживать такие случаи в уровнях доступа, чтобы избежать дополнительного усложнения инфраструктуры. Вместо этого мы разрешили нашим разработчикам использовать в таких случаях чистые .NET API.

Само по себе решение AAL не является большим и было разработано за несколько человеко-месяцев в течение двухлетнего периода. Таким образом, наши начальные инвестиции не были слишком высокими и уже достигли уровня безубыточности благодаря экономии времени на разработке и поддержке.

Разумеется, широко используемая и очень гибкая платформа может стать единой точкой сбоя. Мы ослабили остроту этой проблему за счет полного охвата решения AAL модульными тестами и развертывания его новых версий под тщательным контролем. Вы могли бы возразить, что подход с AAL сам по себе вводит дополнительную сложность в нашу систему и вынуждает наших разработчиков изучать новый уровень абстракции. Но мы считаем, что эти издержки с лихвой компенсируются повышением общей эффективности труда и качества.

Улрик Борн (Ulrik Born) — магистр наук в области информационных технологий (Технический университет Дании), последние 15 лет был разработчиком и архитектором ПО на платформе Windows. Является ведущим разработчиком в Saxo Bank — инвестиционном интернет-банке.

Выражаю благодарность за рецензирование статьи экспертам Йонасу Гудйонссону (Jonas Gudjonsson) из Saxo Bank, Джеймсу Маккафри (James McCaffrey) из Microsoft, Григорию Мельнику (Grigori Melnick) из Microsoft и Фернандо Симонацци (Fernando Simonazzi) из Microsoft.

Контроллеры

Каждый запрос, поступающий в приложение, обрабатывается контроллером. может обрабатывать запрос произвольным образом до тех пор, пока он не пересекает границу ответственности модели и представления. Это означает, что контроллеры не должны содержать или сохранять данные, равно как не генерировать пользовательские интерфейсы.

В инфраструктуре ASP.NET MVC Framework контроллеры являются классами .NET, которые содержат логику, требуемую для обработки запроса. Роль контроллера заключается в инкапсуляции логики приложения. Другими словами, контроллеры отвечают за обработку входящих запросов, выполнение операций над моделью предметной области и выбор представлений для визуализации пользователю.

Пример приложения

Для целей этой и следующих статей мы создадим новый проект MVC по имени ControllersAndActions с использованием шаблона Empty (Пустой), отметив флажок MVC в разделе Add folders and core references for (Добавить папки и основные ссылки для), а также проект модульного тестирования под названием ControllersAndActions.Tests. Модульные тесты, которые будут создаваться, не требуют имитированных реализаций, поэтому пакет Moq устанавливать не придется, но нужно установить пакет MVC, чтобы тесты имели доступ к базовым классам контроллеров.

В окне консоли диспетчера пакетов NuGet среды Visual Studio введите следующую команду:

После создания проекта выберите пункт ControllersAndActions Properties (Свойства ControllersAndActions) в меню Project (Проект) среды Visual Studio, в открывшемся диалоговом окне перейдите на вкладку Web (Веб) и отметьте переключатель Specific Page (Определенная страница) в категории Start Action (Начальное действие). Вводить какое-либо значение не нужно — достаточно только выбора переключателя.

Понятие контроллера

Вы сталкивались со случаями использования контроллеров почти во всех предшествующих статьях, посвященных ASP.NET MVC. Наступило время заглянуть «за кулисы».

Создание контроллера с помощью интерфейса IController

В MVC Framework классы контроллеров должны реализовать интерфейс IController из пространства имен System.Web.Mvc, показанный в примере ниже:

Чтобы получить определение этого интерфейса, необходимо загрузить исходный код MVC Framework, который чрезвычайно полезен для выяснения внутренней работы средств инфраструктуры.

Как видите, интерфейс IController очень прост. Его единственный метод Execute() вызывается, когда запрос направляется этому классу контроллера. Инфраструктура MVC Framework выясняет, на какой класс ориентирован запрос, за счет чтения значения свойства controller, сгенерированного данными маршрутизации, или через специальные классы маршрутизации.

Создавать классы контроллеров можно путем реализации интерфейса IController, однако поскольку этот интерфейс является низкоуровневым, потребуется проделать немало работы, чтобы получить, в конечном счете, что-нибудь полезное. Тем не менее, интерфейс IController полезен для демонстрации оперирования контроллеров и с этой целью в папке Controllers создается новый файл класса по имени BasicController.cs, содержимое которого приведено в примере ниже:

Методу Execute() интерфейса IController передается объект RequestContext, предоставляющий информацию о текущем запросе и маршруте, который ему соответствует (и приводит к вызову данного контроллера для обработки этого запроса). В классе RequestContext определены два свойства, описанные в таблице ниже:

Свойства, определяемые классом RequestContext

Возвращает объект HttpContextBase, который описывает текущий запрос

Возвращает объект RouteData, который описывает маршрут, соответствующий запросу

Объект HttpContextBase предоставляет доступ к набору объектов, описывающих текущий запрос, которые называются объектами контекста; мы еще вернемся к ним позже. Объект RouteData описывает маршрут. Важные свойства класса RouteData перечислены в таблице ниже:

Имя Описание
HttpContext
Свойства, определяемые классом RouteData

Возвращает реализацию RouteBase, которая соответствует маршруту

Возвращает реализацию IRouteHandler, которая обрабатывает маршрут Values

Возвращает коллекцию значений сегментов, индексированную по имени

В статье Настройка системы маршрутизации было показано, как использовать типы RouteBase и IRouteHandler для настройки системы маршрутизации. В рассматриваемом примере с помощью свойства Values получаются значения переменных сегментов controller и action, которые затем записываются в ответ.

Часть проблемы, возникающей при создании специальных контроллеров, связана с отсутствием доступа к таким средствам, как представления. Это означает, что придется работать на более низком уровне, чем и объясняется запись содержимого напрямую в ответ клиенту. Свойство HttpContextBase.Response возвращает объект HttpResponseBase, который позволяет конфигурировать и добавлять содержимое к ответу, предназначенному для отправки клиенту. Это еще одна точка соприкосновения между платформой ASP.NET и инфраструктурой MVC Framework.

Если запустить приложение и перейти на URL вида /Basic/Index, то специальный контроллер сгенерирует вывод, показанный на рисунке ниже:

Реализация интерфейса IController позволяет создать класс, который MVC Framework распознает как контроллер и отправляет ему запросы, безо всяких ограничений относительно того, как запрос обрабатывается, и какой ответ для него генерируется. Это удачный пример, поскольку он показывает, насколько расширяемой может быть инфраструктура MVC Framework даже для ключевых строительных блоков вроде контроллеров, однако написание сложного приложения подобным образом может быть сопряжено с немалыми трудностями.

Классы с именами, заканчивающимися на Base

При обработке запросов инфраструктура MVC Framework полагается на платформу ASP.NET, что имеет большой смысл, т.к. эта платформа является проверенной и многофункциональной реализацией, которая тесно интегрируется с сервером приложений IIS. Проблема заключается в том, что классы, применяемые платформой ASP.NET для предоставления информации о запросах, не очень хорошо подходят для модульного тестирования — основного преимущества использования MVC Framework.


В Microsoft решили ввести возможность тестирования, поддерживая при этом совместимость с существующими приложениями ASP.NET Web Forms, так что в результате появились классы Base. Эти классы так называются из-за того, что они имеют те же самые имена, как у основных классов платформы ASP.NET, за которыми следует слово Base.

Так, например, платформа ASP.NET предоставляет контекстную информацию о текущем запросе и ряде ключевых служб приложения через объект HttpContext. Соответствующим ему классом Base является HttpContextBase, экземпляр которого передается методу Execute(), определенному в интерфейсе IController (в последующих примерах будут продемонстрированы и другие классы Base). В первоначальных классах и классах Base определены одни и те же свойства и методы, но классы Base всегда абстрактны, а это значит, что их легко применять для модульного тестирования.

Иногда вы получите экземпляр одного из первоначальных классов ASP.NET, такого как HttpContext. В таком случае необходимо создать дружественный к MVC класс Base, подобный HttpContextBase. Это делается с использованием одного из классов Wrapper, которые имеют такие же имена, как первоначальные классы, дополненные словом Wrapper, например, HttpContextWrapper. Классы Wrapper являются производными от классов Base и имеют конструкторы, которые принимают экземпляры первоначальных классов:

Первоначальные классы, классы Base и классы Wrapper определены в пространстве имен System.Web, поэтому платформа ASP.NET может гладко поддерживать приложения MVC Framework и более старые приложения Web Forms.

Создание контроллера за счет наследования от класса Controller

Как было продемонстрировано в предыдущем примере, инфраструктура MVC Framework допускает практически неограниченную настройку и расширение. Чтобы обеспечить любой требуемый вид обработки запросов и генерации результатов, можно реализовать интерфейс IController. Вам не нравятся методы действий? Вы не хотите беспокоиться по поводу визуализированных представлений? В таком случае можете взять дело в свои руки и реализовать лучший, быстрый и более элегантный способ обработки запросов. Либо же вы можете воспользоваться средствами, предлагаемыми командой разработчиков MVC Framework из Microsoft, и унаследовать свои контроллеры от класса System.Web.Mvc.Controller.

Класс Controller обеспечивает поддержку обработки запросов, которая знакома большинству разработчиков приложений MVC. Она применялась во всех примерах, рассмотренных в предыдущих статьях. Класс Controller предоставляет три ключевых средства, которые описаны ниже:

Методы действий

Поведение контроллера разнесено по множеству методов (вместо реализации в виде единственного метода Execute()). Каждый метод действия отображается на соответствующий URL и вызывается с параметрами, извлеченными из входящего запроса.

Результаты действий

Можно возвращать объект, описывающий результат выполнения действия (например, визуализация представления либо перенаправление на другой URL или метод действия), и затем обрабатывать его каким угодно образом. Разделение между указанием результатов и их выполнением упрощает модульное тестирование.

Фильтры

Многократно используемое поведение (например, аутентификацию) можно инкапсулировать в виде фильтров и затем помечать каждый аспект поведения контроллеров и методов действий с помощью атрибута в исходном коде.

Если только вы не имеете дело со специфичным требованием, то лучшим подходом к созданию контроллеров будет их наследование от класса Controller, что, как и можно было ожидать, делает среда Visual Studio, когда создает новый класс в ответ на выбор пункта меню Add Scaffold (Добавить Шаблон).

В примере ниже приведен код простого контроллера под названием DerivedController, созданного подобным образом. Он сгенерирован с применением варианта MVC 5 Controller — Empty (Контроллер MVC 5 — Пустой) с несколькими простыми изменениями, предназначенными для установки свойства ViewBag и выбора представления:

Класс Controller также обеспечивает связь с системой представлений Razor. В этом примере мы возвращаем результат вызова метода View(), которому в качестве параметра передается имя представления для визуализации клиенту. Чтобы создать это представление, создайте папку Views/Derived, щелкните на ней правой кнопкой мыши и выберите в контекстном меню пункт Add MVC 5 View Page (Razor) (Добавить Страница представления MVC 5 (Razor)). Укажите в качестве имени MyView.cshtml и щелкните на кнопке ОК для создания файла представления.

Приведите содержимое файла в соответствие с примером:

После запуска приложения и перехода на URL вида /Derived/Index этот метод действия вызывается, а представление MyView визуализируется:

Наследование от класса Controller приводит к необходимости в реализации методов действий, получении любых входных данных, необходимых для обработки запроса, и генерации подходящего ответа. В следующих статьях описано множество подходов, позволяющих делать это.

Платформа Microsoft .NET. Обзор архитектуры и возможностей

Проблемы разработки современных информационных систем

Проблемы интеграции

  • Модулей, написанных на различных языках, использующих разный API (или версии API) или разный формат представления данных;
  • Программ, разработанных для различных платформ, в рамках единого программного комплекса;
  • Систем, использующих разные программные модели.

Особенно часто возникают проблемы интеграции с унаследованным кодом ( legacy ). При решении задач интеграции возникают проблемы несовместимости.

Проблемы переносимости

Все чаще к программам предъявляются требования поддержки нескольких платформ (например, возможность работы с программой на платформе Windows и Mac OS).

Проблемы версий

Windows-разработчики знают о проблеме совместимости версий, известной под названием «ад DLL». Этот «ад» возникает, когда компоненты, устанавливаемые для нового приложения, заменяют компоненты старого приложения. В итоге старое приложение начинает работать неправильно или перестает работать.

Управление ресурсами

Одной из проблем программирования является управление и корректное освобождение ресурсов, файлов, памяти, пространства экрана, сетевых соединений, ресурсов баз данных и т. д. Некорректное управление этими ресурсами может привести к некорректному выполнению программы.

Безопасность типов

Когда упоминают проблему безопасности типов, имеют в виду некорректное обращение с типами данных: попытки обратиться к областям памяти за границей типа, попытки вызвать методы, отсутствующие у типа, или попытки вызвать метод, принимающий в качестве параметра тип А, и передать ему в качестве параметра объект типа В.

Обработка сбоев

При разработке Windows-приложений с использованием Win32 API некоторые функции возвращают исключения, другие — коды состояний, третьи — HRESULT . Таким образом, отсутствует согласованный механизм обработки сбоев и есть возможность игнорировать некоторые исключения, что делает код небезопасным.

Эти и другие проблемы разработки информационных систем помогает решать платформа Microsoft .NET.

Решение проблем разработки информационных систем в .NET

Один из способов решения проблемы неоднородности — разработка и поддержка стандартных программных интерфейсов, облегчающих задачу переноса приложений на серверы различных платформ. Однако приложения могут использовать базы данных , коммуникационные и другие сервисы, интерфейсы которых не являются компонентами языка или среды программирования. Другой способ, применяемый производителями для решения проблемы неоднородности, — поддержка стандартных протоколов. Системы, поддерживающие один и тот же протокол, могут взаимодействовать друг с другом, даже если они опираются на различные машинные архитектуры и операционные системы.

Технология . NET представляет собой способ разработки и развертывания программного обеспечения, который с помощью таких широко используемых стандартов, как HTTP и XML , реализует взаимодействие программ и обеспечивает доступ через Internet к многочисленным программным сервисам. Технология включает . NET Framework — платформу для разработки и исполнения приложений, которая упрощает и ускоряет разработку, поддерживает полноценное объектно-ориентированное программирование для Web , устраняет многие типы наиболее распространенных программных ошибок, предоставляет общий API для всех языков.

Что составляет Microsoft .NET

. NET Framework — инфраструктура разработки приложений. Ее основные компоненты — общеязыковая исполняющая среда (Common Language Runtime) и библиотека классов . NET Framework Class Library .

Общеязыковая исполняющая среда (Common Language Runtime)

Common Language Runtime (CLR) — общеязыковая исполняющая среда, абстрагирующая сервисы операционной системы и исполняющая управляемые приложения, любое действие которых должно получить разрешение со стороны CLR.

Весь код для платформы .NET преобразуется CLR в промежуточный код на языке CIL. Поэтому разработчики могут легко интегрировать код, написанный для .NET на различных языках программирования. Все, что можно сделать на одном .NET-совместимом языке (за редким исключением), можно сделать на любом другом. Код на этих языках компилируется в код на одном языке — языке CIL.

CLR расположена поверх операционной системы и предоставляет виртуальную среду для управляемых приложений. Код для платформы .NET либо исполняется CLR, либо получает разрешение на исполнение за ее пределами.

Код для CLR представляет собой команды псевдомашинного языка Common Intermediate Language (CIL). Эти команды компилируются в машинный код соответствующего типа процессора по запросу (just-in-time) в период выполнения. Обычно компиляция метода происходит один раз во время его первого вызова. Затем результат кэшируется в памяти, чтобы избежать задержек при повторных вызовах. JIT-компилятор выполняет оптимизацию кода специально для процессора, на котором исполняется этот код.

Преобразуя команды CIL в команды процессора, JIT-компилятор выполняет верификацию кода на предмет безопасности типов.

Практически невозможно выполнить команду, обращающуюся к области памяти, к которой у этой команды нет разрешения на доступ. В управляемом приложении устраняется проблема ошибочно инициализированных указателей, запрещается преобразовать тип в нечто, чем он не является, так как это нарушение безопасности типов. CLR не позволяет вызывать методы с разрушенным стековым фреймом.

Ресурсы, выделяемые управляемым кодом, освобождаются сборщиком мусора. Иначе говоря, программист только выделяет память, но не освобождает ее — это делает CLR. Сборщик мусора отслеживает все ссылки на объекты, создаваемые программой, и уничтожает эти объекты, когда занимаемая ими память требуется где-то еще. Таким образом в приложениях с управляемым кодом разрешается проблема утечек памяти.

Верификация кода также является основой способности CLR выполнять несколько приложений внутри одного процесса. Процесс разделяется на виртуальные отсеки — домены приложений ( application domain ). Таким образом повышается эффективность использования памяти, выделяемой процессам. Домены приложений не менее безопасны, чем процессы, так как их границы не могут быть нарушены управляемыми приложениями.

.NET Framework >В . NET включены сборки библиотеки классов . NET Framework Class library ( FCL ), содержащие определения нескольких тысяч типов, каждый из которых предоставляет некоторую функциональность. Наборы «родственных» типов собраны в отдельные пространства имен. Так, пространство имен System содержит базовый класс Object , из которого в конечном счете порождаются все остальные типы.

Таким образом, всякая сущность в . NET является объектом со своими полями и методами.

Кроме того, System содержит типы для целых чисел, символов, строк, обработки исключений, консольного ввода/вывода, группу типов для безопасного преобразования одних типов в другие, форматирования данных, генерации случайных чисел и выполнения математических операций. Типами из пространства имен System пользуются все приложения.

Для изменения существующего FCL -типа можно создать свой собственный производный тип . Можно создавать свои собственные пространства имен. Все это будет четко соответствовать принципам, предлагаемым платформой . NET

Приведем некоторые наиболее распространенные пространства имен и краткое описание содержащихся там типов.

Свойство Описание
Route
RouteHandler
Основные пространства имен FCL
Пространство имен Содержание
System Фундаментальные типы данных и вспомогательные классы
System.Collections Хэш-таблицы, массивы переменной размерности и другие контейнеры
System.Data Классы ADO .NET для доступа к данным
System.Drawing Классы для вывода графики (GDI+)
System.IO Классы файлового и потокового ввода/вывода
System.Net Классы для работы с сетевыми протоколами, например с HTTP
System.Reflection Классы для чтения и записи метаданных
System.Runtime.Remoting Классы для распределенных приложений
System.ServiceProcess Классы для создания служб Wndows
System.Threading Классы для создания и управления потоками
System.Web Классы для поддержки HTTP
System.Web.Services Классы для разработки web-сервисов
System.Web.Services. Классы для разработки клиентов web-сервисов Protocols
System.Web.UI Основные классы, используемые ASP .NET
System.Web.UI. WebControls Серверные элементы управления ASP .NET
System.Wndows.Forms Классы для приложений с графическим интерфейсом пользователя
System.Xml Классы для чтения и ввода данных в формате XML

Все управляемые приложения используют библиотеку классов FCL . Это упрощает интеграцию приложений и позволяет легче переносить приложения с одного языка на другой.

Итоги

Инфраструктура . NET Framework поддерживает разработку и исполнение различных приложений. . NET Framework ставит своей целью решение следующих задач:

  • предоставление объектно-ориентированной среды программирования;
  • предоставление среды исполнения, решающей проблемы конфликта версий;
  • предоставление среды безопасного исполнения кода (безопасность типов и другие особенности управляемого кода);
  • предоставление среды исполнения, улучшающей производительность за счет управления памятью и кэширования результатов компиляции;
  • улучшение интеграции и переносимости приложений за счет использования общего промежуточного языка и библиотеки типов.

. NET Framework состоит из двух основных компонент : общеязыковой исполняющей среды ( CLR ) и библиотеки классов . NET Framework.

Илон Маск рекомендует:  Что такое код socket_create_listen
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL