Наверное многие, изучая спецификацию, уже представили какие можно создать классы для упрощения разработки. Но не стоит изобретать "велосипед". Команда проекта Katana предлагает готовые решения.
Owin.Types
С помощью NuGet добавим в проект еще одну библиотеку – Owin.Types:
PM> Install-Package Owin.Types
В ней размещаются несколько очень полезных классов. Для краткости здесь не будем перечислять все свойства и методы. Их имена достаточно понятны и в процессе разработки доступны через IntelliSense.
OwinConstants
Как уже было сказано ранее, в спецификации перечислены имена, которые являются ключами для получения объектов из словаря типа IDictionary<string, object>. Хорошей практикой является использование констант вместо строковых значений. Поэтому в Katana существует статический класс OwinConstants, в котором поля содержат текстовые значения ключей. С его помощью можно, например, строку env["owin.ResponseHeaders"] заменить на env[OwinConstants.ResponseHeaders].
OwinRequest и OwinResponse
Работать со словарем, даже используя OwinConstants, не очень удобно. Поэтому легко предположить, что многие разработчики создадут для него свои адаптеры.
Авторы Katana предусмотрели это и предлагают два класса: OwinRequest (запрос) и OwinResponse (ответ). Кроме предоставления удобного доступа к данным, второй класс содержит несколько полезных вспомогательных методов:
- Write() – позволяет записать в ответ текстовую строку;
- WriteAsync() – тоже самое, но асинхронно;
- SendFileAsync() – асинхронно передает указанный файл клиенту;
- SetHeader() – устанавливает значение для указанного заголовка.
OwinWebSocket
Еще один класс-адаптер, который представляет реализацию WebSocket для OWIN (соответствующие ключи описаны в расширении спецификации для WebSocket).
OwinHelpers
Данный класс содержит набор статических вспомогательных методов для работы с заголовками, адресами и прочими параметрами запроса или ответа. Часть их, с помощью дополнительного OwinRequestExtensions, определены как расширения класса OwinRequest.
Пример
Напишем модуль, который будет выводить текст по запросу страницы about. Но основная цель – для анализа запроса и формирования ответа использовать OwinRequest и OwinResponse.
namespace OwinDemo
{
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Owin.Types;
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;
public class AboutModule
{
private readonly AppFunc _next;
public AboutModule(AppFunc next)
{
if (next == null)
throw new ArgumentNullException("next");
this._next = next;
}
public Task Invoke(IDictionary<string, object> env)
{
try {
var request = new OwinRequest(env);
var path = request.Path.TrimEnd(new[] { '/' });
if (path.Equals("/About", StringComparison.OrdinalIgnoreCase)) {
var response = new OwinResponse(env);
return response.WriteAsync("About page");
}
}
catch (Exception ex) {
var tcs = new TaskCompletionSource<object>();
tcs.SetException(ex);
return tcs.Task;
}
return this._next(env);
}
}
}
Остается зарегистрировать модуль в классе Startup с учетом порядка вызова: после LoggerModule, но до установки варианта по умолчанию:
...
public void Configuration(IAppBuilder appBuilder)
{
appBuilder.Use(typeof(LoggerModule), "Log Module >");
appBuilder.Use(typeof(AboutModule));
appBuilder.Properties["builder.DefaultApp"] = new AppFunc(
...
Если теперь запустить проект, то при запросе адреса /about данный модуль выведет текст "About page" .
Итак, использование классов из библиотеки Owin.Types позволяет не изобретать велосипед и делает разработку модулей более удобной. Эту тему и продолжим рассматривать дальше.
Исходный код проекта (C#, Visual Studio 2012):
OwinDemo-part4.zip