Re: Шаблон распаковки веб-запроса (Корень компоновки для веб-приложения)
От: RushDevion Россия  
Дата: 13.05.24 18:38
Оценка: 7 (2)
Z>По сути, веб-приложение — это на самом деле два отдельных приложения: веб-клиент и веб-сервис, которые обмениваются между собой запросами-сообщениями.
Эээ... интересная постановка вопроса
Ну как бы да, серверная и клиентская части — это совершенно разные приложения.
Единственно, что их связывает — это протокол прикладного уровня. Стандартный — HTTP(s), FTP, SMTP, SSH и т.п., либо какой-то кастомный — REST over HTTP(s), SOAP over HTTP(s), GRPC over HTTP2 и т.п.
И пишут их зачастую разные люди и даже на разных языках программирования.

Z>Значит, в начальной точке веб-сервиса должно быть создано несколько объектов:

Z>- объект синтаксического разбора (распаковки) запроса
Z>- объект-контроллер для обработки запроса
Z>- объект упаковки результата
Z>- и много других объектов, которые создаются в корне компоновки, которые необходимы для работы сервиса

Собственно, нет. В том смысле, что эти объекты, конечно, нужны, но создавать каждый из них в явном виде в точке сборки не надо.
Для серверной части main может быть вот таким простым:
// Собственно, вот и весь composition root.
var config = ReadConfigFromSomeWhere();
var webServer = new WebServer(new WebServerOptions { BindAddress = config.ListenAddress, Port = config.ListenPort }, new MyRouter());
webServer.Start();
// А уже в конструкторе WebServer может быть что-то вроде:
//  this._router = router; // IRouter, который приходит как параметр конструктора
//  this._socket = new Socket(); // сокет, на котором слушаются входящие подключения
//  this._inputBuffer = new Buffer();   // Буфер для входящих данных
//  this._outputBuffer = new Buffer();  // Буфер для исходящих данных
//  this._parser = new HttpProtocolParser(this._inputBuffer); // Парсер http-протокола
//  и т.д. и т.п.
//
//  WebServer будет оперировать этими внутренними объектами, получать сырые байты, разбирать их в объекты HttpRequest и отдавать на обработку в заданный снаружи IRouter.Handle(httpRequest, httpResponse).

Далее в реализации роутера может быть, например, так:
public class MyRouter: IRouter {
  private JsonSerializer _json = new();  // Вот здесь объекты тоже создаются уже "внутри" реализации, нет необходимости тащить их в composition root
  private QueryStringParser _qsParser = new(); 

  public void Process(HttpRequest httpRequest, HttpResponse httpResponse) {
    object responseObj = ((httpRequest.Method, httpRequest.Path)) switch {
      // Здесь снова конкретный обработчик (контроллер) создается по месту, а не в composition root
      case ("POST", "api/users") => new UsersController().CreateUser(_json.Deserialize<CreateUserRequestDto>(request.Body)); 
      case ("GET", "api/users") => new UsersController().ListUsers(_qsParser.Parse<UsersFilterDto>(request.QueryString));
      case ("POST", "api/orders") => new OrdersController().PlaceOrder(_json.Deserialize<PlaceOrderRequest>(request.Body));
      _ => throw new NotFoundException();
    }
    httpResponse.SetStatusCode(200);
    httpResponse.Write(_json.Serialize(responseObj));
  }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.