﻿
{"id":21162,"date":"2021-03-16T18:10:36","date_gmt":"2021-03-16T18:10:36","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=21162"},"modified":"2021-03-16T18:10:36","modified_gmt":"2021-03-16T18:10:36","slug":"onion-architectureda-cqrs-mediatr-pattern-automapper-fluent-validation","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/onion-architectureda-cqrs-mediatr-pattern-automapper-fluent-validation\/","title":{"rendered":"Onion Architecture&#8217;da CQRS + MediatR Pattern + AutoMapper + Fluent Validation"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>\u00d6nceki yaz\u0131lar\u0131m\u0131zdan <a href=\"https:\/\/www.gencayyildiz.com\/blog\/nedir-bu-onion-architecture-tam-teferruatli-inceleyelim\/\" rel=\"noopener noreferrer\" target=\"_blank\">Nedir Bu Onion Architecture? Tam Teferruatl\u0131 \u0130nceleyelim<\/a> ba\u015fl\u0131kl\u0131 makalemizde inceledi\u011fimiz Onion Architecture \u00fczerinde ya\u015fanabilecek bir tak\u0131m problemleri ele alacak ve bunlara <a href=\"https:\/\/www.gencayyildiz.com\/blog\/cqrs-pattern-nedir-mediatr-kutuphanesi-ile-nasil-uygulanir\/\" rel=\"noopener noreferrer\" target=\"_blank\">CQRS Pattern<\/a> ile \u00e7\u00f6z\u00fcm getirmeye \u00e7al\u0131\u015faca\u011f\u0131z.<\/p>\n<h3>Problemleri Tan\u0131yal\u0131m<\/h3>\n<p>\u0130lgili makaleye g\u00f6z atarsan\u0131z e\u011fer &#8216;Presentation&#8217; katman\u0131ndaki API uygulamas\u0131ndan d\u0131\u015f d\u00fcnyan\u0131n taleplerine kar\u015f\u0131l\u0131k \u00fcretilen datalar &#8216;Domain&#8217; katman\u0131ndaki entity&#8217;ler t\u00fcr\u00fcnde sunulmaktad\u0131r. Bu tarz bir sunum biz geli\u015ftiriciler taraf\u0131ndan pek tercih edilebilir bir durum de\u011fildir. Nihayetinde &#8216;Application&#8217; katman\u0131nda DTO nesnelerimiz mevcuttur ve controller&#8217;lar bu DTO&#8217;lar\u0131 a\u015f\u0131p direkt &#8216;Domain&#8217;de ki entity&#8217;lere ula\u015f\u0131yorsa e\u011fer burada tasar\u0131msal bir sak\u0131nca var demektir. B\u00f6yle bir durumda controller, istek neticesinde verileri entity t\u00fcr\u00fcnde elde etmekte ve bu elde edilen verileri client&#8217;a sunabilmek i\u00e7in DTO d\u00f6n\u00fc\u015f\u00fcm\u00fcnden(conversion) sorumlu olmaktad\u0131r. Halbuki bu conversion i\u015fleminden sorumlu olan controller de\u011fil, &#8216;Application&#8217; katman\u0131d\u0131r. Veri sorgulan\u0131rken &#8216;Application&#8217; katman\u0131ndan \u00f6yle ya da b\u00f6yle DTO t\u00fcr\u00fcnde gelmeli ve controller herhangi bir d\u00f6n\u00fc\u015f\u00fcmle ya da t\u00fcr ile ilgili i\u015flemlerle ilgilenmeksizin gelen datay\u0131 d\u0131\u015f d\u00fcnyaya g\u00f6ndermelidir.<\/p>\n<h3>\u00c7\u00f6z\u00fcm<\/h3>\n<p>Controller&#8217;lar da ki conversion sorumlulu\u011funun ar\u0131nd\u0131r\u0131l\u0131p &#8216;Application&#8217; katman\u0131na verilebilmesi ve b\u00f6ylece &#8216;Presentation&#8217; katman\u0131 a\u00e7\u0131s\u0131ndan direkt olarak talep edilen datan\u0131n entity ve DTO t\u00fcrleriyle, ne \u015fekilde hangi \u015fartlarda d\u00f6n\u00fc\u015f\u00fcm\u00fcn ve e\u015fle\u015ftirmenin ger\u00e7ekle\u015ftirildi\u011fiyle ilgilenmeksizin &#8216;Application&#8217;dan talep edilmesi ve m\u00fcmk\u00fcn mertebe Action metotlar da ger\u00e7ekle\u015ftirilen operasyonlar\u0131n sadele\u015ftirilebilmesi i\u00e7in MediatR k\u00fct\u00fcphanesi e\u015fli\u011finde CQRS pattern&#8217;i kullanaca\u011f\u0131z.<\/p>\n<h3>Pratik Uygulama<\/h3>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern.png\" alt=\"Onion Architecture&#039;da CQRS + MediatR Pattern\" width=\"359\" height=\"623\" class=\"alignleft size-full wp-image-21169\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern.png 359w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-173x300.png 173w\" sizes=\"auto, (max-width: 359px) 100vw, 359px\" \/><\/a>\u00d6ncelikle &#8216;Application&#8217; katman\u0131na <a href=\"https:\/\/www.nuget.org\/packages\/MediatR\/\" rel=\"noopener noreferrer\" target=\"_blank\">MediatR<\/a> ve <a href=\"https:\/\/www.nuget.org\/packages\/MediatR.Extensions.Microsoft.DependencyInjection\/\" rel=\"noopener noreferrer\" target=\"_blank\">MediatR.Extensions.Microsoft .DependencyInjection<\/a> isimli k\u00fct\u00fcphaneleri kural\u0131m. Ard\u0131ndan ilgili katmanda &#8216;Features&#8217; isimli klas\u00f6r i\u00e7erisinde &#8216;Commands&#8217; ve &#8216;Queries&#8217; isimli iki klas\u00f6r olu\u015ftural\u0131m ve CQRS pattern yap\u0131lanmas\u0131n\u0131 burada kural\u0131m.<\/p>\n<p>Esas\u0131nda buradaki t\u00fcm &#8216;..Request&#8217; ve &#8216;..Response&#8217; s\u0131n\u0131flar\u0131 sistemdeki DTO s\u0131n\u0131flar\u0131na kar\u015f\u0131l\u0131k gelmektedir. Amma velakin bizler CQRS pattern&#8217;\u0131 daha d\u00fczenli olu\u015fturabilmek i\u00e7in sistemi bu \u015fekilde in\u015fa etmeyi tercih edece\u011fiz. Sizlere de tavsiyem bu y\u00f6ndedir. Aksi taktirde say\u0131lar\u0131 artt\u0131k\u00e7a hangi DTO hangi command ya da query&#8217;nin oldu\u011fu haddinden fazla kompleksle\u015fecektir.<\/p>\n<p>Burada yap\u0131lanman\u0131n kayna\u011f\u0131na dair herhangi bir \u00f6rnek g\u00f6stermenin gere\u011fi yok kanaatindeyim. Nihayetinde yukar\u0131da da adresini referans etti\u011fim ve \u00f6nceden klavyeye alm\u0131\u015f oldu\u011fum <a href=\"https:\/\/www.gencayyildiz.com\/blog\/cqrs-pattern-nedir-mediatr-kutuphanesi-ile-nasil-uygulanir\/\" rel=\"noopener noreferrer\" target=\"_blank\">CQRS Pattern<\/a> makalemizde bu yap\u0131lanman\u0131n ne oldu\u011funu ve hangi mant\u0131kla in\u015fa edildi\u011fini tam teferruatl\u0131 ele alm\u0131\u015f bulunmaktay\u0131z.<\/p>\n<h3>AutoMapper Konfig\u00fcrasyonu<\/h3>\n<p>Tabi CQRS pattern&#8217;\u0131 kullan\u0131rken bir yandan da Handle s\u0131n\u0131flar\u0131ndaki conversion\/mapping operasyonlar\u0131n\u0131n <a href=\"https:\/\/www.gencayyildiz.com\/blog\/asp-net-coreda-automapper-kullanimi\/\" rel=\"noopener noreferrer\" target=\"_blank\">AutoMapper<\/a> k\u00fct\u00fcphanesiyle ne \u015fekilde daha pratik hale getirildi\u011fini g\u00f6zlemleyebilmek i\u00e7in herhangi bir handler s\u0131n\u0131f\u0131n\u0131n i\u00e7eri\u011fini a\u015fa\u011f\u0131ya alal\u0131m.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class GetAllProductQueryHandler : IRequestHandler&lt;GetAllProductQueryRequest, List&lt;GetAllProductQueryResponse&gt;&gt;\r\n    {\r\n        readonly IProductRepository _productRepository;\r\n        IMapper _mapper;\r\n        public GetAllProductQueryHandler(IProductRepository productRepository, IMapper mapper)\r\n        {\r\n            _productRepository = productRepository;\r\n            _mapper = mapper;\r\n        }\r\n        public async Task&lt;List&lt;GetAllProductQueryResponse&gt;&gt; Handle(GetAllProductQueryRequest request, CancellationToken cancellationToken)\r\n        {\r\n            var products = await _productRepository.GetAsync();\r\n            return _mapper.Map&lt;List&lt;GetAllProductQueryResponse&gt;&gt;(products);\r\n        }\r\n    }\r\n<\/pre>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere handler s\u0131n\u0131flar\u0131nda repository \u00fczerinden entity t\u00fcr\u00fcnde elde edilen datalar response nesnelerine &#8216;IMapper&#8217; \u00fczerinden h\u0131zl\u0131ca d\u00f6n\u00fc\u015ft\u00fcr\u00fclmektedir. Bunun i\u00e7in &#8216;Application&#8217; katman\u0131ndaki &#8216;Mapping&#8217; klas\u00f6r\u00fc i\u00e7erisinde;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class GeneralMapping : Profile\r\n    {\r\n        public GeneralMapping()\r\n        {\r\n            CreateMap&lt;Product, GetAllProductQueryResponse&gt;()\r\n                .ReverseMap();\r\n            CreateMap&lt;Product, GetByIdProductQueryResponse&gt;()\r\n                .ReverseMap();\r\n            CreateMap&lt;Product, GetWhereProductQueryResponse&gt;()\r\n                .ReverseMap();\r\n        }\r\n    }\r\n<\/pre>\n<p>i\u00e7eri\u011fine sahip bir &#8216;Profile&#8217; s\u0131n\u0131f\u0131n\u0131n tan\u0131mlanmas\u0131 yeterli olacakt\u0131r.<\/p>\n<p>T\u00fcm bu i\u015flemlerden sonra &#8216;Application&#8217; katman\u0131n\u0131n &#8216;ServiceRegistration&#8217; s\u0131n\u0131f\u0131nda a\u015fa\u011f\u0131daki konfig\u00fcrasyonlar\u0131n yap\u0131lmas\u0131 gerekmektedir;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    static public class ServiceRegistration\r\n    {\r\n        public static void AddApplicationServices(this IServiceCollection serviceCollection)\r\n        {\r\n            serviceCollection.AddMediatR(Assembly.GetExecutingAssembly());\r\n            serviceCollection.AddAutoMapper(Assembly.GetExecutingAssembly());\r\n        }\r\n    }\r\n<\/pre>\n<p>Geriye &#8216;Presentation&#8217; katman\u0131ndaki Web API uygulamas\u0131nda bu servisleri kullanan a\u015fa\u011f\u0131daki controller&#8217;\u0131n tasarlanmas\u0131 kalmaktad\u0131r;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    &#x5B;Route(&quot;api\/&#x5B;controller]&quot;)]\r\n    &#x5B;ApiController]\r\n    public class ProductsController : ControllerBase\r\n    {\r\n        IMediator _mediator;\r\n        public ProductsController(IMediator mediator)\r\n        {\r\n            _mediator = mediator;\r\n        }\r\n\r\n        &#x5B;HttpGet]\r\n        public async Task&lt;List&lt;GetAllProductQueryResponse&gt;&gt; Get()\r\n        {\r\n            return await _mediator.Send(new GetAllProductQueryRequest());\r\n        }\r\n\r\n        &#x5B;HttpGet(&quot;{Id}&quot;)]\r\n        public async Task&lt;GetByIdProductQueryResponse&gt; Get(&#x5B;FromQuery] GetByIdProductQueryRequest request)\r\n        {\r\n            return await _mediator.Send(request);\r\n        }\r\n\r\n        &#x5B;HttpGet(&quot;search\/{Name}&quot;)]\r\n        public async Task&lt;List&lt;GetWhereProductQueryResponse&gt;&gt; Get(&#x5B;FromQuery] GetWhereProductQueryRequest request)\r\n        {\r\n            return await _mediator.Send(request);\r\n        }\r\n\r\n        &#x5B;HttpPost]\r\n        public async Task&lt;CreateProductCommandResponse&gt; Post(&#x5B;FromBody] CreateProductCommandRequest request)\r\n        {\r\n            return await _mediator.Send(request);\r\n        }\r\n    }\r\n<\/pre>\n<p>\u0130\u015fte bu kadar&#8230; G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere bu tarz bir tasar\u0131m sayesinde controller&#8217;lar client&#8217;a iletilecek verinin t\u00fcr\u00fcyle yahut conversion i\u015flemleriyle ilgilenmemekte, direkt olarak i\u015f kural\u0131n\u0131 uygulay\u0131p geriye sonu\u00e7 d\u00f6nmektedirler.<\/p>\n<h3>Fluent Validation Konfig\u00fcrasyonu<\/h3>\n<p>Handle operasyonlar\u0131nda client&#8217;lardan gelecek olan verileri do\u011frulamam\u0131z gerekebilmektedir. Bunun i\u00e7in en etkili k\u00fct\u00fcphanelerden biri olan <a href=\"https:\/\/www.gencayyildiz.com\/blog\/net-core-fluentvalidation-ile-validasyon-kontrolu\/\" rel=\"noopener noreferrer\" target=\"_blank\">FluentValidation<\/a>&#8216;\u0131 kullanabiliriz.<br \/>\n<div id=\"attachment_21198\" style=\"width: 593px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-AutoMapper-Fluent-Validation-2.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-21198\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-AutoMapper-Fluent-Validation-2.png\" alt=\"Onion Architecture&#039;da CQRS + MediatR Pattern + AutoMapper + Fluent Validation\" width=\"583\" height=\"206\" class=\"size-full wp-image-21198\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-AutoMapper-Fluent-Validation-2.png 583w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-AutoMapper-Fluent-Validation-2-300x106.png 300w\" sizes=\"auto, (max-width: 583px) 100vw, 583px\" \/><\/a><p id=\"caption-attachment-21198\" class=\"wp-caption-text\">T\u00fcm bu k\u00fct\u00fcphaneleri Application katman\u0131na y\u00fckleyiniz&#8230;<\/p><\/div><\/p>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-AutoMapper-Fluent-Validation.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-AutoMapper-Fluent-Validation.png\" alt=\"Onion Architecture&#039;da CQRS + MediatR Pattern + AutoMapper + Fluent Validation\" width=\"277\" height=\"125\" class=\"alignleft size-full wp-image-21191\" \/><\/a>Fluent Validation k\u00fct\u00fcphanesi Validator s\u0131n\u0131flar\u0131 \u00fczerinden do\u011frulama ger\u00e7ekle\u015ftirmektedir. Onion Architecture&#8217;da Validator s\u0131n\u0131flar\u0131n\u0131 &#8216;Features&#8217; alt\u0131nda ilgili Command yahut Query alt\u0131nda olu\u015fturmam\u0131z yeterli olacakt\u0131r.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class CreateProductCommandValidator : AbstractValidator&lt;CreateProductCommandRequest&gt;\r\n    {\r\n        public CreateProductCommandValidator()\r\n        {\r\n            RuleFor(p =&gt; p.Name)\r\n                .NotNull()\r\n                .WithMessage(&quot;L\u00fctfen 'Name'i bo\u015f ge\u00e7meyiniz.&quot;)\r\n                .MaximumLength(20)\r\n                .MinimumLength(3)\r\n                .WithMessage(&quot;'Name' de\u011feri 3 ile 20 karakter aras\u0131nda olmal\u0131d\u0131r.&quot;);\r\n            RuleFor(p =&gt; p.Price)\r\n                .Must(p =&gt; p &gt; 0)\r\n                .WithMessage(&quot;L\u00fctfen 'Price' de\u011ferini do\u011fru giriniz.&quot;);\r\n        }\r\n    }\r\n<\/pre>\n<p>Ard\u0131ndan bu validator&#8217;\u0131 t\u00fcrl\u00fc y\u00f6ntemlerle i\u015fleyebilir ve kullanabiliriz. Misal ben burada &#8216;ValidationFilter&#8217; isminde bir filter olu\u015fturaca\u011f\u0131m ve ilgili validasyonlar\u0131 burada kontrol edece\u011fim. Tabi bu filter&#8217;\u0131 &#8216;Infrastructure&#8217; katman\u0131nda olu\u015fturmam\u0131z daha do\u011fru olacakt\u0131r. Haliyle a\u015fa\u011f\u0131daki gibi bir tasar\u0131m neticesinde i\u015flemimizi ger\u00e7ekle\u015ftiriyoruz;<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-AutoMapper-Fluent-Validation-1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-AutoMapper-Fluent-Validation-1.png\" alt=\"Onion Architecture&#039;da CQRS + MediatR Pattern + AutoMapper + Fluent Validation\" width=\"230\" height=\"132\" class=\"aligncenter size-full wp-image-21195\" \/><\/a><\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class ValidationFilter : IAsyncActionFilter\r\n    {\r\n        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)\r\n        {\r\n            if (!context.ModelState.IsValid)\r\n            {\r\n                var errors = context.ModelState\r\n                    .Where(x =&gt; x.Value.Errors.Count &gt; 0)\r\n                    .ToDictionary(e =&gt; e.Key, e =&gt; e.Value.Errors.Select(e =&gt; new\r\n                    {\r\n                        e.ErrorMessage\r\n                    })).ToArray();\r\n\r\n                context.Result = new BadRequestObjectResult(errors);\r\n                return;\r\n            }\r\n            await next();\r\n        }\r\n    }\r\n<\/pre>\n<p>\u0130lgili filter&#8217;\u0131 olu\u015fturduktan sonra &#8216;Presentation&#8217; katman\u0131ndaki &#8216;WebAPI&#8217; projesinin &#8216;Startup.cs&#8217; dosyas\u0131nda a\u015fa\u011f\u0131daki konfig\u00fcrasyonu ger\u00e7ekle\u015ftirelim.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class Startup\r\n    {\r\n        .\r\n        .\r\n        .\r\n        public void ConfigureServices(IServiceCollection services)\r\n        {\r\n            services.AddApplicationServices();\r\n            services.AddPersistenceServices(Configuration);\r\n            services.AddInfrastructureServices();\r\n\r\n            services.AddControllers(options =&gt; options.Filters.Add&lt;ValidationFilter&gt;())\r\n                .AddFluentValidation(configuration =&gt; configuration\r\n                    .RegisterValidatorsFromAssemblyContaining&lt;Application.Features.Commands.CreateProduct.CreateProductCommandValidator&gt;())\r\n                .ConfigureApiBehaviorOptions(o =&gt; o.SuppressModelStateInvalidFilter = true);\r\n            .\r\n            .\r\n            .\r\n        }\r\n        .\r\n        .\r\n        .\r\n    }\r\n<\/pre>\n<p>Burada <em><strong>12<\/strong><\/em> ile <em><strong>15.<\/strong><\/em> sat\u0131rlar aras\u0131na g\u00f6z atarsan\u0131z e\u011fer ilgili entegrasyon sa\u011flanmaktad\u0131r. <em><strong>12.<\/strong><\/em> sat\u0131rda <code style=\"color:red;\">AddControllers(options =&gt; options.Filters.Add&lt;ValidationFilter&gt;())<\/code> komutu ile geli\u015ftirilen ValidationFilter isimli filter&#8217;\u0131 uygulamaya dahil ediyoruz. <em><strong>13.<\/strong><\/em> sat\u0131rda ise Fluent Validation k\u00fct\u00fcphanesini uygulamaya entegre ediyor ve <em><strong>14.<\/strong><\/em> sat\u0131rda ise validator s\u0131n\u0131flar\u0131n\u0131n hangi assembly&#8217;den okunaca\u011f\u0131n\u0131 bildiriyoruz. Son olarak da <em><strong>15.<\/strong><\/em> sat\u0131rda model state&#8217;lerinin otomatik kontrol edilmesini pasifle\u015ftiriyoruz. B\u00f6ylece art\u0131k her bir istek geldi\u011finde ilgili filter tetiklenecek ve validation kontrol\u00fc sa\u011flam\u0131\u015f olacakt\u0131r. Uygun olmayan bir model post edildi\u011fi zaman a\u015fa\u011f\u0131dakine benzer bir hata al\u0131nacakt\u0131r.<\/p>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-AutoMapper-Fluent-Validation-3.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-AutoMapper-Fluent-Validation-3.png\" alt=\"Onion Architecture&#039;da CQRS + MediatR Pattern + AutoMapper + Fluent Validation\" width=\"524\" height=\"356\" class=\"aligncenter size-full wp-image-21205\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-AutoMapper-Fluent-Validation-3.png 524w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/Onion-Architectureda-CQRS-MediatR-Pattern-AutoMapper-Fluent-Validation-3-300x204.png 300w\" sizes=\"auto, (max-width: 524px) 100vw, 524px\" \/><\/a><\/p>\n<p>B\u00f6ylece Onion Architecture \u00fczerinde CQRS + MediatR pattern&#8217;\u0131n nas\u0131l uyguland\u0131\u011f\u0131n\u0131 ve akabinde AutoMapper ile conversion i\u015flemlerinin nas\u0131l otomatize edildi\u011fini ve Fluent Validation sayesinde de validation kontrol\u00fcn\u00fcn nas\u0131l yap\u0131ld\u0131\u011f\u0131n\u0131 kombine olarak incelemi\u015f olduk. Umar\u0131m verimli olmu\u015ftur&#8230;<\/p>\n<p>\u0130lgilenenlerin faydalanmas\u0131 dile\u011fiyle&#8230;<br \/>\nSonraki yaz\u0131lar\u0131mda g\u00f6r\u00fc\u015fmek \u00fczere&#8230;<br \/>\n\u0130yi \u00e7al\u0131\u015fmalar&#8230;<\/p>\n<p>Not : \u00d6rnek projeyi indirmek i\u00e7in <a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/03\/ProductExample.zip\">buraya<\/a> t\u0131klay\u0131n\u0131z.<\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>Merhaba, \u00d6nceki yaz\u0131lar\u0131m\u0131zdan Nedir Bu Onion Architecture? Tam Teferruatl\u0131 \u0130nceleyelim ba\u015fl\u0131kl\u0131 makalemizde inceledi\u011fimiz Onion Architecture \u00fczerinde ya\u015fanabilecek bir tak\u0131m problemleri ele alacak ve bunlara CQRS Pattern ile \u00e7\u00f6z\u00fcm getirmeye \u00e7al\u0131\u015faca\u011f\u0131z. Problemleri Tan\u0131yal\u0131m \u0130lgili makaleye&#46;&#46;&#46;<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":21001,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2739,12],"tags":[4150,4162,4151,4157,4153,4159,4144,4160,4161,4163],"class_list":["post-21162","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-core","category-c-sharp-c","tag-cqrs","tag-cqrs-automapper","tag-cqrs-pattern","tag-mediator-pattern","tag-mediatr","tag-mediatr-library","tag-onion-architecture","tag-onion-architecture-cqrs","tag-onion-architecture-cqrs-mediatr","tag-onion-architecture-automapper"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/21162","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/comments?post=21162"}],"version-history":[{"count":38,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/21162\/revisions"}],"predecessor-version":[{"id":21209,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/21162\/revisions\/21209"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/21001"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=21162"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=21162"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=21162"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}