Microsoft OWIN и конвейер обработки запросов ASP.NET. Часть вторая, спецификация OWIN и его реализация компанией Microsoft. Проект Katana, общее описание.

OWIN – открытый интерфейс веб-сервера для .NET (Open Web Server Interface for .NET). Или говоря по другому – это спецификация определяющая абстакцию посредством которой взаимодействуют веб-сервер и веб-приложение. Более подробное описание спецификации можно найти на сайте owin.org, а если более конкретно, то тут. Чтобы легче было себе представить, нужно взглянуть на рисунок приведённый ниже.

Правая диаграмма показывает общую схему структуры приложения, которое использует спецификацию OWIN для организации взаимодействия между компонентами всей инфраструктуры. Левая – схему структуры веб-приложений в Windows без использования этой спецификации, то есть то, что было раньше (есть и сейчас и будет в будущем). Если применить спецификацию OWIN  к связке IIS/ASP.NET, то получится примерно следующее.

Замечу сразу, что если быть более точным, то ни правая диаграмма первого рисунка и ни данная, в абсолютной точности не выражают схему организации структуры. Все дело в том, что нельзя просто так взять и отделить части схемы на независимые куски. Просто, на мой взгляд, для быстрого восприятия материала, они являются наиболее оптимальными для иллюстрации общей картины. Ну а дальше всё постепенно прояснится. Вернувшись к теме сразу возникает вопрос: а зачем лишний уровень абстракции и в без того перегруженный конвейер IIS/ASP.NET ? Отвечу коротко – почти незачем, просто это одна из реализаций организации работы приложения по спецификации OWIN с использованием IIS/ASP.NET. Остальные выводы будут сделаны в конце статьи. В самом начале статьи упоминалось о взаимодействии сервера и приложения, на практике, такое взаимодействие сводится к использованию функций с сигнатурой одного единственного делегата, так называемого делегата приложения. Который имеет следующий вид:

 using AppFunc = Func<IDictionary<string, object>, Task>;

Входной параметр имеющий тип IDictionary<string, object> и называемый – словарь окружения, содержит все данные (переменные сервера, данные запроса и т.п.). Он не может иметь значение null, а так же быть пустым. Кроме того, должен содержать некоторые ключи определённые спецификацией. Выходной параметр имеет тип Task – инкапсулирует некоторую выполняемую задачу. На основе данного делегата строятся компонеты приложения и объединяются в цепочку, тем самым формируется конвейер обработки запросов OWIN, куда передаётся запрос на обработку. Из типа возвращаемого делегатом уже видно, что он будет работать в асинхронном режиме. Пока, всё описанное выше – это только теория. Microsft OWIN или проект под названием Katana является реализацией спецификации OWIN компанией Microsoft. Исходный код проекта полность открытый и находится на CodePlex по следующему адресу. На момент написания статьи текущая версия 3.0.0 Alpha, а RTM версия – 2.1.0. Именно последняя будет описана и использоваться в дальнейшем. Ниже представлена визуальная схема архитектуры проекта Katana, согласно спецификации OWIN.

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

Ниже представлены схематические изображения архитектуры веб-приложений использующих Katana и работающих по спецификации OWIN.

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

 namespace Owin
{
    using System;
    using System.Collections.Generic;
 
    public interface IAppBuilder
    {
        object Build(Type returnType);
        IAppBuilder New();
        IAppBuilder Use(object middleware, params object[] args);
 
        IDictionary<string, object> Properties { get; }
    }
}

Интерфейс не является частью спецификации. Тут есть очень тонкий момент: вся инфраструктура работает по спецификации OWIN, а данная абреввиатура на диаграммах, наглядно показывает просто конкретную реализацию промежуточного слоя. Теперь, чтобы лучше понять материал я покажу как создать очень простое веб-приложение, которое будет работать по спецификации OWIN. Для начала нам нужен хост, процесс в Windows в котором будет работать наше приложение. Для этого создадим простое консольное приложение в Visual Studio 2013.

Естественно, реализация спецификации OWIN задача ресурсоёмкая, поэтому и есть проект Katana. Воспользуемся некоторыми готовыми компонентами Katana, установив их через NuGet.

Как видно из рисунка выше, было установлено четыре сборки. Сборка OWIN, содержит один едниственный интерфейс – IAppBuilder, который был описан выше. Microsoft.Owin – содержит множество вспомагательных типов, которые облегчают создание разных  компонетов Owin. Например: OwinRequest, OwinResponse, OwinContext и т.д. Сборка Microsoft.Owin.Hosting содержит типы необходимые для хостинга и запуска приложения. Ну а сборка Microsoft.Owin.Host.HttpListener содержит дефолтовый сервер OwinHttpListener проекта Katana. Это по сути обёртка вокруг стандартного System.Net.HttpListener. Для конфигурации приложения при запуске, Katana ищет класс Startup. В качестве шаблонного элемента он присутсвует в Visual Studio 2013. Добавим его. Более подробно об алгоритме поиска класса Startup написано тут.

Осталось добавить код, запускающий сервер:

 using System;
using Microsoft.Owin.Hosting;
 
namespace SimpleOwinApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            const string uri = "https://localhost:8088/";
 
            using(WebApp.Start<Startup>(uri))
            {
                Console.WriteLine("Server started");
                Console.ReadKey();
                Console.WriteLine("Server stoped");
            }
        }
    }
}

и код конфигурации.

 using Owin;
using Microsoft.Owin;
 
[assembly: OwinStartup(typeof(SimpleOwinApplication.Startup))]
 
namespace SimpleOwinApplication
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.Run(context =>
            {
                context.Response.ContentType = "text/html";
                return context.Response.WriteAsync(htmlText);
            });
        }
 
        private const string htmlText = "<html>" +
                                          "<head>" +
                                              "<title></title>" +
                                          "</head>" +
                                          "<body>" +
                                              "<h1>Simple Owin Application<h1>" +
                                          "</body>" +
                                        "</html>";
    }
} 

Ничего особенного тут не происходит. Просто на все запросы к хосту, сервет отвечает куском кода HTML. В следующей части все детали конвейера OWIN и его компоненты будут расмотрены более детально.

Запускаем приложение, и видим что всё работает. Здесь находится ссылка на проект. Тут уже назревает вопрос: зачем нам всё это, плохо ли было без этого? Конечно нет, но если посмотреть с другой стороны, то инфраструктура веб-приложения построенная по спецификации OWIN при помощи управляемого кода даёт нам полную свободу действий и гибкость, еcли мы реализуем её без использования существующей. То есть, если мы не используем IIS/ASP.NET. Лично я не вижу смысла использовать спецификацию OWIN в приложениях IIS/ASP.NET, об этом будет ещё написано в следующих статьях. Почему не стоит? Да потому, что конвейер IIS/ASP.NET и без того перегружен. Незачем вводить ещё один дополнительный слой абстракции. И к тому же технология ASP.NET достаточно зрелая и используя накопленные возможности и опыт можно решить очень широкий круг задач, что мы и делали до сих пор и будем делать. Вывод – спецификация OWIN позволяет пересмотреть  архитектуру веб-инфраструктуры не принося ничего нового в уже существующую, но позволяющая построить совершенно новую и полностью управляемую архитектуру инфраструктуры.