Мой Byndyusoft.обновление Инфраструктуры | Ddd + Cqrs + Webapi

Всем привет! Я часто ищу в Интернете «идеальную архитектуру», и несколько месяцев назад я наткнулся на интересную реализацию и хотел бы поделиться ею немного дальше.

Ссылка на реализацию Немного модернизации и я получил полностью универсальный рабочий шаблон.

Для тех, кто не знаком с DDD, вы можете начать с вики .

В итоге мы получим комбинацию DDD + CQRS + Entity Framework + OData + WebApi + Log4Net + Castle Windsor + Kendo UI. Звучит громоздко, но чисто лично для меня в результате получается достаточно легко масштабируемая система.

Конечный результат будет примерно таким Кликабельное изображение (на весь экран)

Мой Byndyusoft.Обновление инфраструктуры | DDD + CQRS + WebApi

Итак, начнем… Создайте папку «Домен и инфраструктура».

В папке Domain создаем 3 проекта (библиотеку классов):

  1. Домен.

    Команды

  2. Домен.

    База данных

  3. Домен.

    Модель

В папке Infrastrcuture создаем 4 проекта (библиотеку классов):
  1. Инфраструктура.

    Веб

  2. Инфраструктура.

    Домен

  3. Инфраструктура.

    EntityFramework

  4. Инфраструктура.

    Легирование

А само веб-приложение (ASP MVC5), назовем его Интернет (с шаблоном MVC).

И последний проект (библиотека классов) Веб приложение .

А теперь о каждом более подробно: CQRS (разделение ответственности за командный запрос) Немного о командах и запросах Запросы : методы возвращают результат без изменения состояния объекта.

Другими словами, Query не имеет никаких побочных эффектов.

Команды : методы изменяют состояние объекта, не возвращая значения.

На самом деле эти методы правильнее называть модификаторами или мутаторами, но исторически они назывались командами.

В проекте Domain.Commands мы будем хранить команды, которые будут менять состояние объекта и нашу бизнес-логику.

Вот что у нас будет Команда .

И мы будем использовать OData в качестве запроса.

В проекте Command.Database мы будем хранить схему базы данных (я обычно использую для этого PowerDesigner) и Seed-скрипты.

Мы храним все сущности в проекте Domain.Model. Теперь папка Инфраструктура.

Infrastrcuture.Domain — храним все помощники домена, построители команд, исключения, которые понадобятся для модели Домена.

Infrastrcuture.EntityFramework — это наша ORM. Infrastrcuture.Logging — ведение журнала.

Infrastrcuture.Web — веб-помощники, расширения, обработчики форм.

В проекте Web.Application. Создайте базовый класс для чтения (OData): ReadODataControllerBase.cs

  
  
  
   

namespace Web.Application { using System.Linq; using System.Web.Http.OData; using Infrastructure.Domain; using Infrastructure.EntityFramework; public class ReadODataControllerBase<TEntity> : ODataController where TEntity : class, IEntity { private readonly IRepository<TEntity> _repository; public ReadODataControllerBase(IRepository<TEntity> repository) { _repository = repository; } public IQueryable<TEntity> Get() { return _repository.Query(); } } }

И базовый контроллер формы: Формконтроллербасе.

cs

namespace Web.Application { using System; using System.Net; using System.Web.Mvc; using Castle.Core.Logging; using Castle.Windsor; using Infrastrcuture.Web.Forms; using Infrastructure.Domain.Exceptions; using Infrastructure.EntityFramework; using Services.Account; using Services.Account.Models; public class FormControllerBase : Controller, ICurrentUserAccessor { public JsonResult Form<TForm>(TForm form) where TForm : IForm { var formHanlderFactory = ResolveFormHandlerFactory(); var unitOfWork = ResolveUnitOfWork(); var logger = ResolveLogger(); try { logger.Info($"Begin request of <{CurrentUser.DisplayNameWithNk}> with form <{ form.GetType().

Name }>.

"); formHanlderFactory.Create<TForm>().

Execute(form); unitOfWork.SaveChanges(); logger.Info($"Complete request of <{CurrentUser.DisplayNameWithNk}> with form <{ form.GetType().

Name }>.

"); return Json(new { form }); } catch (BusinessException be) { return JsonError(form, be, logger); } catch (FormHandlerException fhe) { return JsonError(form, fhe, logger); } catch (Exception e) { return JsonError(form, e, logger); } } //Add exception logging public FileResult FileForm<TForm>(TForm form) where TForm : IFileForm { var formHanlderFactory = ResolveFormHandlerFactory(); formHanlderFactory.Create<TForm>().

Execute(form); return File(form.FileContent, System.Net.Mime.MediaTypeNames.Application.Octet, form.FileName); } private JsonResult JsonError<TForm>(TForm form, Exception e, ILogger logger) { logger.Error($"Rollback request of <{CurrentUser.DisplayNameWithNk}> with form <{ form.GetType().

Name }>.

", e); Response.TrySkipIisCustomErrors = true; Response.StatusCode = (int)HttpStatusCode.InternalServerError; return Json(new { form, exceptionMessage = e.Message }); } #region Dependency resolution private IFormHandlerFactory ResolveFormHandlerFactory() { return GetContainer().

Resolve<IFormHandlerFactory>(); } private IUnitOfWork ResolveUnitOfWork() { return GetContainer().

Resolve<IUnitOfWork>(); } private ILogger ResolveLogger() { return GetContainer().

Resolve<ILogger>(); } private IWindsorContainer GetContainer() { var containerAccessor = HttpContext.ApplicationInstance as IContainerAccessor; return containerAccessor.Container; } private ICurrentUserKeeper ResolveCurrentUserKeeper() { return GetContainer().

Resolve<ICurrentUserKeeper>(); } #endregion #region CurrentUserAccessor Memebers public ApplicationUser CurrentUser { get { var currentUserKeeper = ResolveCurrentUserKeeper(); return currentUserKeeper.GetCurrentUser(); } } #endregion } }

В итоге для чтения данных из базы мы просто создаем класс и наследуем его от класса ReadODataController и просто переходим в локальный хост :12345/odata/Станции.

Весь запрос записывает для нас OData: СтанцииController.cs

namespace Web.Application.Station { using Domain.Model.Station; using Infrastructure.EntityFramework; public class StationsController : ReadODataControllerBase<Station> { public StationsController(IRepository<Station> repository) : base(repository) { } } }

Одатаконфиг.

cs Одатаконфиг.

cs

namespace Web { using System.Linq; using System.Web.Http; using System.Web.Http.OData.Builder; using System.Web.Http.OData.Extensions; using Domain.Model.Station; using Infrastrcuture.Web.Extensions; using Microsoft.Data.Edm; public class ODataConfig { public static void Register(HttpConfiguration config) { var builder = new ODataConventionModelBuilder(); config.Routes.MapODataServiceRoute("odata", "odata", GetEdmModel(builder)); } public static IEdmModel GetEdmModel(ODataConventionModelBuilder builder) { var entityTypes = typeof (Station).

Assembly.GetTypes().

Where(x => x.IsClass && !x.IsNested); var method = builder.GetType().

GetMethod("EntitySet"); foreach (var entityType in entityTypes) { var genericMethod = method.MakeGenericMethod(entityType); genericMethod.Invoke(builder, new object[] { entityType.Name.Pluralize() }); } return builder.GetEdmModel(); } } }

Этот шаблон уже был протестирован и сейчас один из наших проектов нормально работает в продакшене, без каких-либо проблем.

Ссылка на проект: NTemplate Теги: #C++ #.

NET #ddd #cqrs #Виндзорский замок #.

NET #C++

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.