Sisk

Обработчики HTTP‑сервера

Эта страница переведена с английского автоматически. Читать оригинал

В версии Sisk 0.16 мы представили класс HttpServerHandler, который предназначен для расширения общего поведения Sisk и предоставления дополнительных обработчиков событий, таких как обработка HTTP‑запросов, маршрутизаторов, контекстных пакетов и прочего.

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

Смотрите this page, чтобы узнать, где каждый событие вызывается и какова его цель. Вы также можете посмотреть lifecycle of an HTTP request, чтобы понять, что происходит с запросом и где генерируются события. HTTP‑сервер позволяет использовать несколько обработчиков одновременно. Каждый вызов события синхронный, то есть текущий поток блокируется для каждого запроса или контекста, пока не будут выполнены и завершены все обработчики, связанные с этой функцией.

В отличие от RequestHandlers, они не могут быть применены к отдельным группам маршрутов или конкретным маршрутам. Вместо этого они применяются ко всему HTTP‑серверу. Вы можете задавать условия внутри вашего Http Server Handler. Кроме того, для каждого HttpServerHandler в каждом приложении Sisk создаётся единственный экземпляр (singleton), то есть существует только один объект HttpServerHandler.

Практический пример использования HttpServerHandler — автоматическое освобождение соединения с базой данных в конце обработки запроса.

C#
// DatabaseConnectionHandler.cs

public class DatabaseConnectionHandler : HttpServerHandler
{
    protected override void OnHttpRequestClose(HttpServerExecutionResult result)
    {
        var requestBag = result.Request.Context.RequestBag;

        // проверяет, определён ли у запроса DbContext
        // в его контекстном пакете
        if (requestBag.IsSet<DbContext>())
        {
            var db = requestBag.Get<DbContext>();
            db.Dispose();
        }
    }
}

public static class DatabaseConnectionHandlerExtensions
{
    public static DbContext GetDbContext(this HttpRequest request)
    {
        return request.Bag.GetOrAdd(() => new DbContext());
    }
}

С помощью приведённого кода расширение GetDbContext позволяет создать контекст соединения непосредственно из объекта HttpRequest. Неосвобождённое соединение может вызвать проблемы при работе с базой данных, поэтому оно закрывается в OnHttpRequestClose.

Вы можете зарегистрировать обработчик на HTTP‑сервере в вашем билдере или напрямую через HttpServer.RegisterHandler.

C#
// Program.cs

class Program
{
    static void Main(string[] args)
    {
        using var app = HttpServer.CreateBuilder()
            .UseHandler<DatabaseConnectionHandler>()
            .Build();

        app.Router.MapInstance(new UserController());
        app.Start();
    }
}

Таким образом, класс UsersController может использовать контекст базы данных следующим образом:

C#
// UserController.cs

[RoutePrefix("/users")]
public class UserController : ApiController
{
    [RouteGet()]
    public async Task<HttpResponse> List(HttpRequest request)
    {
        var db = request.GetDbContext();
        var users = db.Users.ToArray();

        return JsonOk(users);
    }

    [RouteGet("<id>")]
    public async Task<HttpResponse> View(HttpRequest request)
    {
        var db = request.GetDbContext();

        int userId = request.RouteParameters["id"].GetInteger();
        var user = db.Users.FirstOrDefault(u => u.Id == userId);

        return JsonOk(user);
    }

    [RoutePost]
    public async Task<HttpResponse> Create(HttpRequest request)
    {
        var db = request.GetDbContext();
        var user = await request.GetJsonContentAsync<User>();

        ArgumentNullException.ThrowIfNull(user);

        db.Users.Add(user);
        await db.SaveChangesAsync();

        return JsonMessage("User added.");
    }
}

В приведённом коде используются методы JsonOk и JsonMessage, встроенные в ApiController, который наследуется от RouterController:

C#
// ApiController.cs

public class ApiController : RouterModule
{
    public HttpResponse JsonOk(object value)
    {
        return new HttpResponse(200)
            .WithContent(JsonContent.Create(value, null, new JsonSerializerOptions()
            {
                PropertyNameCaseInsensitive = true
            }));
    }

    public HttpResponse JsonMessage(string message, int statusCode = 200)
    {
        return new HttpResponse(statusCode)
            .WithContent(JsonContent.Create(new
            {
                Message = message
            }));
    }
}

Исключения, выбрасываемые обработчиками #

Начиная с Sisk 1.7, исключения, выбрасываемые обработчиками сервера, обрабатываются следующим образом:

  • Исключения, возникшие в OnServerStarting, OnServerStarted и OnSetupRouter, останавливают запуск сервера. Они оборачиваются в InvalidOperationException с оригинальным исключением в InnerException.
  • Исключения, возникшие в других событиях, записываются в ErrorsLogsStream, а остальные обработчики продолжают вызываться, если только не включён ThrowExceptions. При включённом ThrowExceptions они также оборачиваются в InvalidOperationException.
  • Исключения, возникшие в OnHttpRequestClose и OnException, а также при форматировании журналов доступа и ошибок, никогда не попадают в HTTP‑движок, даже при включённом ThrowExceptions. Они записываются в ErrorsLogsStream. В более ранних версиях такие исключения могли завершать процесс или оставлять соединение открытым.

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

Интеграция проста: обработчики регистрируются во время настройки сервера. Класс HttpServerHandler предоставляет мощный набор инструментов для управления ресурсами и расширения поведения Sisk в HTTP‑приложениях.

Sisk распространяется с открытым исходным кодом по лицензии MIT.

Начните вводить, чтобы искать по документации и справочнику API.