Контроллеры MVC должны быть тонкими маршрутными драйверами. В общем, ваши действия контроллера должны быть похожи на
[Authorize(Roles = "User,Admin"]
[GET("hosts")]
public ActionResult Hosts(int id)
{
if (false == ModelState.IsValid)
return new HttpStatusCodeResult(403, "Forbidden for reasons....");
var bizResponse = bizService.DoThings();
if(bizResponse == null) return HttpNotFound(id + "could not be found")
if(false == bizResponse.Success)
return new HttpStatusCodeResult(400, "Bad request for reasons....");
return View(bizResponse);
}
Вы также можете обобщить состояние модели проверки и проверку объекта ответа (если вы используете общий договор - базовый тип или интерфейс), чтобы просто:
[Authorize(Roles = "User,Admin"]
[GET("hosts")]
[AutoServiceResponseActionFilter]
public ActionResult Hosts(int id)
{
var bizResponse = bizService.DoThings();
return View(bizResponse);
}
Я сторонник использования сериализации для перехода от бизнес-уровня к уровню http/MVC/ASP.NET. Все, что вы используете, не должно генерировать никаких HTTP или tcp-запросов, если оно находится в процессе и должно использовать named-pipes для переноса в памяти. WCF с IDesign InProcFactory дает вам это из коробки, вы не можете эмулировать это очень хорошо WebApi, вы можете эмулировать это с помощью NFX или Service Stack, но я не уверен в этом.
Если вы хотите, чтобы bizService был размещен вне процесса, лучшим транспортом на этом этапе является использование шины сообщений или очереди сообщений в bizService. Как правило, при работе с этой архитектурой вам нужен действительно асинхронный интерфейс, который, когда конечная точка HTTP принимает запрос, может сразу получить ответ http OK или http ACCEPTED и быть проинформирован позже о выполнении этого действия.
Как правило, конечная точка MVC-контроллера/ASP.NET-http не должна инициировать HTTP-запрос. Ваш bizService, если необходимо, может бесплатно позвонить в сторонний http-сервис. В конечном счете, звонки в оба конца - это то, что убивает воспринимаемую производительность всего. Если вы не можете избежать звонков в оба конца, вы должны стремиться ограничить его не более чем одним для чтения и не более одного для записи. Если вам необходимо вызвать многократные чтения и несколько вызовов для записи по кабелю, что очень хорошо иллюстрирует плохой архитектурный дизайн бизнес-системы.
И наконец, в хорошо спроектированной SOA ваша система намного более функциональна, чем OO. Функциональная логика с неизменяемыми данными/отсутствие общего состояния - это то, что масштабы. Чем больше вы зависите от любого общего состояния, тем хрупкой является система и начинает активно становиться anti -scale. Быть высококонцентрированным может легко привести к системам, которые разрушаются в диапазоне 20-50 req/s. Номинально единая серверная система должна обрабатывать 300-500 req/s реального использования.
Причина для таких бизнес-сервисов, как это, заключается в том, чтобы следовать шаблону доверенной подсистемы. Ни один пользователь не может аутентифицироваться в вашем бизнес-сервисе, только ваше приложение может аутентифицироваться. Ни один пользователь не может определить, где размещаются ваши бизнес-сервисы. В связи с этим пользователи не должны разрешать самим бизнес-службам, бизнес-сервис Действие должно иметь возможность авторизовать отправителя запроса, если это необходимо. В общем, это необходимо только для мелкозернистого управления, например, отдельные записи могут быть запрещены пользователем.
Поскольку клиенты являются удаленными и ненадежные (пользователи могут злонамеренно манипулировать ими, являются ли они JavaScript или скомпилированных двоичных файлов), они никогда не должны иметь каких-либо знаний вашего уровня обслуживания. Сам сервисный уровень можно буквально отключить от всего Интернета, только позволяя вашим веб-серверам общаться с уровнем обслуживания. На вашем веб-сервере может быть какая-то логика построения презентации, например, посев вашего клиента с именем userId, именем, маркерами безопасности и т. Д., Но это, вероятно, будет минимальным. Это веб-сервер, выступающий в качестве прокси-сервера, которому необходимо инициировать вызовы на уровень обслуживания
Краткая версия, только контроллер должен называть ваш сервисный уровень.
Одно из исключений, если вы используете систему очередности сообщений, например, Azure Service Bus, в зависимости от ограничений безопасности, пользовательский интерфейс может быть в порядке, чтобы напрямую помещать сообщения в ASB, поскольку ASB можно рассматривать как DMZ и все еще защищает ваши услуги от любых знаний клиента. Основной риск прямого доступа к очереди - злонамеренный пользователь может наводнить вашу очередь для атаки типа отказа в обслуживании (и вы потратите деньги). Нездоровый риск заключается в том, что если вы измените контракт на очередь устаревших клиентов, это может привести к многочисленным мёртвым письмам или ядовитым сообщениям
Я действительно верю, что будущее всей разработки - это клиенты, которые непосредственно передают сообщения, но текущая технология очень не хватает для делая это легко и надежно. Прямой доступ к очереди будет необходим для будущего Интернета вещей. Веб-серверы просто не имеют возможности получать непрерывные потоки событий от тысяч или миллионов лампочек и холодильников.
Hi Chris, Итак, если я использую сервисный уровень между представлением и слоем данных, вызов для служебного уровня должен поступать из пользовательского интерфейса, а не из контроллера? или я могу сделать вызов для обслуживания через разностный уровень (вид прокси-класса)? Спасибо. – hollycrab
@hollycrab добавил еще к моему сообщению –
Hi Chris, Я понял. Большое спасибо. – hollycrab