{"id":2918,"date":"2019-12-24T12:29:11","date_gmt":"2019-12-24T11:29:11","guid":{"rendered":"https:\/\/gokhan-gokalp.com\/?p=2918"},"modified":"2019-12-24T12:29:11","modified_gmt":"2019-12-24T11:29:11","slug":"getting-started-with-clean-architecture-using-asp-net-core-02","status":"publish","type":"post","link":"https:\/\/gokhan-gokalp.com\/tr\/getting-started-with-clean-architecture-using-asp-net-core-02\/","title":{"rendered":"Getting Started with Clean Architecture using ASP.NET Core \u2013 02"},"content":{"rendered":"<\/p>\r\n<blockquote class=\"wp-block-quote\">\r\n<p><span style=\"font-size: inherit;\">Hen\u00fcz makalenin ilk b\u00f6l\u00fcm\u00fcn\u00fc okumad\u0131ysan\u0131z, konuyu daha iyi anlayabilmek ad\u0131na <\/span><a style=\"font-size: inherit;\" href=\"https:\/\/gokhan-gokalp.com\/getting-started-with-clean-architecture-using-asp-net-core-01\/\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"buradan (opens in a new tab)\"><em>buradan<\/em><\/a><span style=\"font-size: inherit;\"> ula\u015fabilirsiniz.<\/span><\/p>\r\n<\/blockquote>\r\n<p><!-- \/wp:post-content --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Makalenin bu ikinci b\u00f6l\u00fcm\u00fcnde ise, <strong>clean architecture<\/strong> konsept&#8217;inin <em>.NET Core<\/em> ile minimal d\u00fczeyde implementasyon i\u015fleminden bahsedece\u011fim.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u00d6rnek olarak, i\u00e7erisinde film ekleyebilece\u011fimiz ve listeleyebilece\u011fimiz basit bir <em>API<\/em> geli\u015ftirece\u011fiz.<\/p>\r\n<p><a href=\"\/wp-content\/uploads\/2019\/10\/clean_architecture_2.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-2900 lazyload\" data-src=\"\/wp-content\/uploads\/2019\/10\/clean_architecture_2.jpg\" alt=\"\" width=\"752\" height=\"533\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2019\/10\/clean_architecture_2.jpg 752w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2019\/10\/clean_architecture_2-300x213.jpg 300w\" data-sizes=\"(max-width: 752px) 100vw, 752px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 752px; --smush-placeholder-aspect-ratio: 752\/533;\" \/><\/a><\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:gallery {\"ids\":[2900]} --><\/p>\r\n<figure class=\"wp-block-gallery columns-1 is-cropped\"><\/figure>\r\n<p><!-- \/wp:gallery --><\/p>\r\n<p><!-- wp:heading --><\/p>\r\n<h2>Application Domain&#8217;in Implementasyonu<\/h2>\r\n<p><!-- \/wp:heading --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u0130lk \u00f6nce architecture&#8217;\u0131n kalbi olacak olan application domain k\u0131sm\u0131n\u0131 olu\u015fturaca\u011f\u0131z.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u00d6ncesinde ise k\u0131saca &#8220;<em>Application Domain<\/em>&#8221; i hat\u0131rlayal\u0131m. Bu layer database, <em>UI<\/em> vb. framework\u2019lerden isolated bir \u015fekilde architecture&#8217;\u0131n ortas\u0131nda konumlanmaktad\u0131r. Temel olarak i\u00e7erisinde ise domain modellerini, use-case&#8217;leri ve external interface&#8217;leri bar\u0131nd\u0131rmaktad\u0131r.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u0130lk olarak \u201c<em>Minimal.Core<\/em>\u201d isminde bir class library&#8217;si olu\u015ftural\u0131m.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<pre class=\"wp-block-code\"><code>dotnet new classlib -n Minimal.Core<\/code><\/pre>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Ard\u0131ndan bu library i\u00e7erisinde \u201c<em>Models<\/em>\u201d isminde bir klas\u00f6r olu\u015ftural\u0131m ve domain modellerini a\u015fa\u011f\u0131daki gibi i\u00e7erisinde tan\u0131mlayal\u0131m.<\/p>\r\n<pre class=\"lang:default decode:true\">using System;\r\n\r\nnamespace Minimal.Core.Models\r\n{\r\n    public abstract class EntityBase\r\n    {\r\n        public Guid Id { get; set; }\r\n        public DateTime CreatedAt { get; set; }\r\n        public DateTime ModifiedAt { get; set; }\r\n    }\r\n}\r\n<\/pre>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<pre class=\"lang:default decode:true\">namespace Minimal.Core.Models\r\n{\r\n    public class Movie : EntityBase\r\n    {\r\n        public string Name { get; set; }\r\n        public double Rating { get; set; }\r\n        public int AgeGroup { get; set; }\r\n        public bool IsDeleted { get; set; }\r\n    }\r\n}<\/pre>\r\n<p>Modelleri tan\u0131mlad\u0131ktan sonra ise port\u2019lar\u0131 tan\u0131mlayaca\u011f\u0131m\u0131z \u201c<em>Interfaces<\/em>\u201d klas\u00f6r\u00fcn\u00fc olu\u015ftural\u0131m. Bu klas\u00f6r i\u00e7erisinde ise \u201c<code>IRepository<\/code>\u201d isminde bir interface\/port tan\u0131mlayal\u0131m.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Bu port sayesinde database i\u015flemlerini, \u201c<em>Application Domain<\/em>\u201d layer i\u00e7erisinde herhangi bir teknolojiye ba\u011f\u0131ml\u0131 olmadan isolated bir \u015fekilde ger\u00e7ekle\u015ftirebilece\u011fiz.<\/p>\r\n<div>\r\n<pre class=\"lang:default decode:true\">using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq.Expressions;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace Minimal.Core.Interfaces\r\n{\r\n    public interface IRepository&lt;T&gt; : IDisposable where T : class\r\n    {\r\n        Task CreateAsync(T entity);\r\n        Task&lt;IEnumerable&lt;T&gt;&gt; GetWhereAsync(Expression&lt;Func&lt;T, bool&gt;&gt; predicate);\r\n    }\r\n}<\/pre>\r\n<\/div>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Port&#8217;u tan\u0131mlad\u0131ktan sonra ise, adapter\u2019ler aras\u0131nda kullanaca\u011f\u0131m\u0131z data transfer objelerini de tan\u0131mlamam\u0131z gerekmektedir.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Bunun i\u00e7in, \u201c<em>Dtos<\/em>\u201d isminde bir klas\u00f6r daha olu\u015ftural\u0131m. Klas\u00f6r\u00fc olu\u015fturduktan sonra i\u00e7erisinde \u201c<code>BaseResponse<\/code>\u201d ve \u201c<code>Movie<\/code>\u201d <em>DTO<\/em>&#8216;lar\u0131n\u0131 a\u015fa\u011f\u0131daki gibi tan\u0131mlayal\u0131m.<\/p>\r\n<pre class=\"lang:default decode:true \">using System.Collections.Generic;\r\nusing System.Linq;\r\n\r\nnamespace Minimal.Core.Dtos\r\n{\r\n    public class BaseResponseDto&lt;TData&gt;\r\n    {\r\n        public BaseResponseDto()\r\n        {\r\n            Errors = new List&lt;string&gt;();\r\n        }\r\n\r\n        public bool HasError =&gt; Errors.Any();\r\n        public List&lt;string&gt; Errors { get; set; }\r\n        public int Total { get; set; }\r\n        public TData Data { get; set; }\r\n    }\r\n}<\/pre>\r\n<pre class=\"lang:default decode:true\">namespace Minimal.Core.Dtos\r\n{\r\n    public class MovieDto\r\n    {\r\n        public string Name { get; set; }\r\n        public double Rating { get; set; }\r\n        public int AgeGroup { get; set; }\r\n    }\r\n}<\/pre>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Request modellerini ise, \u201c<em>Requests<\/em>\u201d isimli bir klas\u00f6r alt\u0131nda toplayaca\u011f\u0131z. Bunun i\u00e7in &#8220;<em>Dtos<\/em>&#8221; klas\u00f6r\u00fc alt\u0131nda, \u201c<em>Requests<\/em>\u201d isimli bir klas\u00f6r daha olu\u015ftural\u0131m.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<pre class=\"wp-block-code\"><code>Minimal.Core\r\n-Models\r\n-Interfaces\r\n-Dtos\r\n--Requests<\/code><\/pre>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Request modellerini olu\u015fturmadan \u00f6nce ise, <em>MediatR<\/em> paketini NuGet \u00fczerinden projeye dahil etmemiz gerekmektedir.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<pre class=\"wp-block-code\"><code>dotnet add package MediatR<\/code><\/pre>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Bu paket sayesinde <strong>API<\/strong> ile <strong>Application Domain<\/strong> aras\u0131ndaki ileti\u015fimi, loosely coupled olarak tek bir noktadan ger\u00e7ekle\u015ftirebilece\u011fiz. Ayr\u0131ca <strong>use-case<\/strong> yakla\u015f\u0131m\u0131n\u0131 da implemente ederken <em>MediatR<\/em> paketinden faydalanaca\u011f\u0131z.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:quote --><\/p>\r\n<blockquote class=\"wp-block-quote\">\r\n<p><em><strong>NOT<\/strong><\/em>: Dilerseniz herhangi bir paket kullanmadan, kendi use-case interface\u2019lerinizi tan\u0131mlayabilir ve implementasyonlar\u0131n\u0131 olu\u015fturabilirsiniz.<\/p>\r\n<\/blockquote>\r\n<p><!-- \/wp:quote --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u015eimdi \u201c<em>Requests<\/em>\u201d klas\u00f6r\u00fc i\u00e7erisinde, movie i\u015flemleri i\u00e7in gerekli olan request modellerini tan\u0131mlayabiliriz. Bunun i\u00e7in &#8220;<code>CreateMovieRequest<\/code>&#8221; ve &#8220;<code>GetBestMoviesForKidsRequest<\/code>&#8221; modellerini a\u015fa\u011f\u0131daki gibi tan\u0131mlayal\u0131m.<\/p>\r\n<pre class=\"lang:default decode:true\">using MediatR;\r\n\r\nnamespace Minimal.Core.Dtos.Requests\r\n{\r\n    public class CreateMovieRequest : IRequest&lt;BaseResponseDto&lt;bool&gt;&gt;\r\n    {\r\n        public string Name { get; set; }\r\n        public double Rating { get; set; }\r\n    }\r\n}<\/pre>\r\n<pre class=\"lang:default decode:true\">using System.Collections.Generic;\r\nusing MediatR;\r\n\r\nnamespace Minimal.Core.Dtos.Requests\r\n{\r\n    public class GetBestMoviesForKidsRequest : IRequest&lt;BaseResponseDto&lt;List&lt;MovieDto&gt;&gt;&gt;\r\n    {\r\n        \r\n    }\r\n}<\/pre>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Modelleri tan\u0131mlarken <em>MediatR<\/em>&#8216;\u0131n &#8220;<em>IRequest<\/em>&#8221; marker interface&#8217;i ile de, modelleri d\u00f6n\u00fc\u015f tipleri ile birlikte i\u015faretleyerek olu\u015fturduk.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Bu noktaya kadar &#8220;<em>Domain<\/em>&#8221; modellerini, &#8220;<em>DTO<\/em>&#8216;lar\u0131&#8221; ve external interface&#8217;leri yani &#8220;<em>Port<\/em>&#8221; lar\u0131 tan\u0131mlam\u0131\u015f olduk.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Art\u0131k business use-case&#8217;lerini implemente etmeye ba\u015flayabiliriz. \u00d6ncelikle &#8220;<em>Minimal.Core<\/em>&#8221; projesi alt\u0131nda, &#8220;<em>Services\/MovieUseCases<\/em>&#8221; klas\u00f6rlerini olu\u015ftural\u0131m.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<pre class=\"wp-block-code\"><code>Minimal.Core\r\n-Models\r\n-Interfaces\r\n-Dtos\r\n--Requests\r\n-Services\r\n--MovieUseCases<\/code><\/pre>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Olu\u015fturmu\u015f oldu\u011fumuz &#8220;<em>MovieUseCases<\/em>&#8221; klas\u00f6r\u00fc alt\u0131nda, movie ile ilgili t\u00fcm use-case\u2019leri implemente edece\u011fiz.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u015eimdi &#8220;<em>MovieUseCases<\/em>&#8221; klas\u00f6r\u00fc alt\u0131nda, &#8220;<code>CreateMovieHandler<\/code>&#8221; isminde bir class olu\u015ftural\u0131m ve movie olu\u015fturma i\u015flemini a\u015fa\u011f\u0131daki gibi implemente edelim.<\/p>\r\n<pre class=\"lang:default decode:true\">using System;\r\nusing System.Threading;\r\nusing System.Threading.Tasks;\r\nusing MediatR;\r\nusing Microsoft.Extensions.Logging;\r\nusing Minimal.Core.Dtos;\r\nusing Minimal.Core.Dtos.Requests;\r\nusing Minimal.Core.Events;\r\nusing Minimal.Core.Interfaces;\r\nusing Minimal.Core.Models;\r\n\r\nnamespace Minimal.Core.Services.MovieUseCases\r\n{\r\n    public class CreateMovieHandler : IRequestHandler&lt;CreateMovieRequest, BaseResponseDto&lt;bool&gt;&gt;\r\n    {\r\n        private readonly IRepository&lt;Movie&gt; _repository;\r\n        private readonly ILogger&lt;CreateMovieHandler&gt; _logger;\r\n        private readonly IMediator _mediator;\r\n\r\n        public CreateMovieHandler(IRepository&lt;Movie&gt; repository, ILogger&lt;CreateMovieHandler&gt; logger, IMediator mediator)\r\n        {\r\n            _repository = repository;\r\n            _logger = logger;\r\n            _mediator = mediator;\r\n        }\r\n\r\n        public async Task&lt;BaseResponseDto&lt;bool&gt;&gt; Handle(CreateMovieRequest request, CancellationToken cancellationToken)\r\n        {\r\n            BaseResponseDto&lt;bool&gt; response = new BaseResponseDto&lt;bool&gt;();\r\n\r\n            try\r\n            {\r\n                var movie = new Movie\r\n                {\r\n                    Name = request.Name,\r\n                    Rating = request.Rating,\r\n                    IsDeleted = false,\r\n                    CreatedAt = DateTime.Now\r\n                };\r\n\r\n                await _repository.CreateAsync(movie);\r\n\r\n                response.Data = true;\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                _logger.LogError(ex, ex.Message);\r\n                response.Errors.Add(\"An error occurred while creating the movie.\");\r\n            }\r\n\r\n            return response;\r\n        }\r\n    }\r\n}<\/pre>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>K\u0131saca neler yapt\u0131\u011f\u0131m\u0131za bir bakal\u0131m.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u00d6ncelikle &#8220;<code>IRequestHandler<\/code>&#8221; interface&#8217;ini implemente ederek, &#8220;<code>CreateMovieHandler<\/code>&#8221; class&#8217;\u0131n\u0131n bir use-case request handler&#8217;\u0131 oldu\u011funu belirttik. Bu handler k\u0131saca &#8220;<code>CreateMovieRequest<\/code>&#8221; model&#8217;ini handle ederek, geriye &#8220;<code>BaseResponseDto<\/code>&#8221; tipinde bir response modeli d\u00f6nmektedir.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Business use-case&#8217;ini ise dummy olarak &#8220;<code>Handle<\/code>&#8221; method&#8217;u i\u00e7erisinde implemente ettik. Burada dikkat etmemiz gereken nokta ise, &#8220;<code>IRepository<\/code>&#8221; interface&#8217;inin kullan\u0131m\u0131d\u0131r.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Dikkat edersek &#8220;<code>IRepository<\/code>&#8221; interface&#8217;i herhangi ba\u015fka bir layer\/adapter i\u00e7erisinde de\u011fil, &#8220;<em>Minimal.Core.Interfaces<\/em>&#8221; i\u00e7erisinde konumlanmaktad\u0131r. Yani &#8220;<em>Minimal.Core<\/em>&#8220;, i\u00e7erisinde tan\u0131mlam\u0131\u015f oldu\u011fumuz external port&#8217;u kullan\u0131yoruz.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Bu sayede &#8220;<code>CreateMovieHandler<\/code>&#8221; use-case&#8217;i, herhangi bir teknoloji de\u011fi\u015fiminden etkilenmeyecektir.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u015eimdi ise \u00e7ocuklar i\u00e7in en iyi filmleri getirecek olan use-case&#8217;i implemente edelim. Bunun i\u00e7in &#8220;<code>GetBestMoviesForKidsHandler<\/code>&#8221; isminde bir class daha olu\u015ftural\u0131m ve a\u015fa\u011f\u0131daki gibi implemente edelim.<\/p>\r\n<pre class=\"lang:default decode:true\">using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Threading;\r\nusing System.Threading.Tasks;\r\nusing MediatR;\r\nusing Microsoft.Extensions.Logging;\r\nusing Minimal.Core.Dtos;\r\nusing Minimal.Core.Dtos.Requests;\r\nusing Minimal.Core.Interfaces;\r\nusing Minimal.Core.Models;\r\n\r\nnamespace Minimal.Core.Services.MovieUseCases\r\n{\r\n    public class GetBestMoviesForKidsHandler : IRequestHandler&lt;GetBestMoviesForKidsRequest, BaseResponseDto&lt;List&lt;MovieDto&gt;&gt;&gt;\r\n    {\r\n        private readonly IRepository&lt;Movie&gt; _repository;\r\n        private readonly ILogger&lt;GetBestMoviesForKidsHandler&gt; _logger;\r\n\r\n        public GetBestMoviesForKidsHandler(IRepository&lt;Movie&gt; repository, ILogger&lt;GetBestMoviesForKidsHandler&gt; logger)\r\n        {\r\n            _repository = repository;\r\n            _logger = logger;\r\n        }\r\n\r\n        public async Task&lt;BaseResponseDto&lt;List&lt;MovieDto&gt;&gt;&gt; Handle(GetBestMoviesForKidsRequest request, CancellationToken cancellationToken)\r\n        {\r\n            BaseResponseDto&lt;List&lt;MovieDto&gt;&gt; response = new BaseResponseDto&lt;List&lt;MovieDto&gt;&gt;();\r\n\r\n            try\r\n            {\r\n                List&lt;MovieDto&gt; movies = (await _repository.GetWhereAsync(m =&gt; m.AgeGroup &lt;= 16)).Select(m =&gt; new MovieDto\r\n                {\r\n                    Name = m.Name,\r\n                    Rating = m.Rating,\r\n                    AgeGroup = m.AgeGroup\r\n                }).ToList();\r\n\r\n                response.Data = movies;\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                _logger.LogError(ex, ex.Message);\r\n                response.Errors.Add(\"An error occurred while getting movies.\");\r\n            }\r\n\r\n            return response;\r\n        }\r\n    }\r\n}<\/pre>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Bu use-case i\u00e7erisinde ise, basit\u00e7e \u00e7ocuklar i\u00e7in uygun olan filmleri getirecek bir logic kodlad\u0131k. Art\u0131k \u00f6rne\u011fimize g\u00f6re application domain katman\u0131 haz\u0131r durumda.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u015eimdi ise database i\u015flemlerini ger\u00e7ekle\u015ftirece\u011fimiz, infrastructure k\u0131sm\u0131na ge\u00e7elim.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:heading --><\/p>\r\n<h2>Infrastructure\u2019\u0131n Implementasyonu<\/h2>\r\n<p><!-- \/wp:heading --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u00d6ncelikle &#8220;<em>Minimal.Infrastructure<\/em>&#8221; isminde bir class library olu\u015ftural\u0131m.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<pre class=\"wp-block-code\"><code>dotnet new classlib -n Minimal.Infrastructure<\/code><\/pre>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Ard\u0131ndan &#8220;<em>Minimal.Core<\/em>&#8221; projesini referans olarak ekleyelim.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p><em>ORM<\/em> olarak <em>EntityFrameworkCore <\/em>kullanaca\u011f\u0131m\u0131z i\u00e7in NuGet \u00fczerinden &#8220;<em>Microsoft.EntityFrameworkCore<\/em>&#8221; paketini de projeye dahil edelim.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>&#8220;<em>Minimal.Core<\/em>&#8221; projesi i\u00e7erisinde hat\u0131rlarsak, dependency flow&#8217;unu tersine \u00e7evirebilmek i\u00e7in &#8220;<code>IRepository<\/code>&#8221; isminde bir port tan\u0131mlam\u0131\u015ft\u0131k. Infrastructure i\u00e7erisinde ise tan\u0131mlam\u0131\u015f oldu\u011fumuz bu port&#8217;u implemente edece\u011fiz.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u0130lk olarak bir <em>DbContext<\/em> olu\u015ftural\u0131m. Bunun i\u00e7in &#8220;<code>AppDbContext<\/code>&#8221; isminde bir class tan\u0131mlayal\u0131m ve a\u015fa\u011f\u0131daki gibi kodlayal\u0131m.<\/p>\r\n<pre class=\"lang:default decode:true\">using Microsoft.EntityFrameworkCore;\r\nusing Minimal.Core.Models;\r\n\r\nnamespace Minimal.Infrastructure\r\n{\r\n    public class AppDbContext : DbContext\r\n    {\r\n        public AppDbContext(DbContextOptions&lt;AppDbContext&gt; options) : base(options)\r\n        { }\r\n\r\n        public DbSet&lt;Movie&gt; Movies { get; set; }\r\n\r\n        protected override void OnModelCreating(ModelBuilder builder)\r\n        {\r\n            base.OnModelCreating(builder);\r\n\r\n            \/\/...\r\n        }\r\n    }\r\n}<\/pre>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u015eimdi repository class&#8217;\u0131n\u0131 implemente edebiliriz.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Bunun i\u00e7in &#8220;<em>Repositories<\/em>&#8221; isminde bir klas\u00f6r olu\u015ftural\u0131m ve ard\u0131ndan &#8220;<code>Repository<\/code>&#8221; class&#8217;\u0131n\u0131 a\u015fa\u011f\u0131daki gibi bu klas\u00f6r i\u00e7erisinde implemente edelim.<\/p>\r\n<pre class=\"lang:default decode:true\">using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Linq.Expressions;\r\nusing System.Threading.Tasks;\r\nusing Microsoft.EntityFrameworkCore;\r\nusing Minimal.Core.Interfaces;\r\nusing Minimal.Core.Models;\r\n\r\nnamespace Minimal.Infrastructure.Repositories\r\n{\r\n    public class Repository&lt;T&gt; : IRepository&lt;T&gt; where T : EntityBase\r\n    {\r\n        private readonly AppDbContext _context;\r\n        private DbSet&lt;T&gt; _dbSet;\r\n\r\n        public Repository(AppDbContext context)\r\n        {\r\n            _context = context;\r\n            _dbSet = context.Set&lt;T&gt;();\r\n        }\r\n\r\n        public async Task CreateAsync(T entity)\r\n        {\r\n            _dbSet.Add(entity);\r\n\r\n            await _context.SaveChangesAsync();\r\n        }\r\n\r\n        public async Task&lt;IEnumerable&lt;T&gt;&gt; GetWhereAsync(Expression&lt;Func&lt;T, bool&gt;&gt; predicate)\r\n        {\r\n            return await _dbSet.Where(predicate).ToListAsync();\r\n        }\r\n\r\n        private bool _disposed = false;\r\n        protected virtual void Dispose(bool disposing)\r\n        {\r\n            if (!_disposed)\r\n            {\r\n                if (disposing)\r\n                {\r\n                    _context.Dispose();\r\n                }\r\n            }\r\n            _disposed = true;\r\n        }\r\n\r\n        public void Dispose()\r\n        {\r\n            Dispose(true);\r\n            GC.SuppressFinalize(this);\r\n        }\r\n    }\r\n}<\/pre>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Yukar\u0131daki kod blo\u011funda, olu\u015fturmu\u015f oldu\u011fumuz db context&#8217;i kullanarak basit bir generic repository implementasyonu ger\u00e7ekle\u015ftirdik. B\u00f6ylece &#8220;<em>Infrastructure<\/em>&#8221; adapter&#8217;\u00fcn\u00fcn implementasyon i\u015flemini de tamamlam\u0131\u015f olduk.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Son olarak, bir de communication adapter&#8217;\u00fcne\/<em>API<\/em>&#8216;\u0131na ihtiyac\u0131m\u0131z var.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:heading --><\/p>\r\n<h2>API&#8217;\u0131n Implementasyonu<\/h2>\r\n<p><!-- \/wp:heading --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Architecture bak\u0131\u015f a\u00e7\u0131s\u0131ndan bakt\u0131\u011f\u0131m\u0131zda, <em>API<\/em>&#8216;\u0131n imlementasyon i\u015fleminin de di\u011fer adapter&#8217;lerin implementasyon i\u015fleminden bir farkl\u0131 yoktur. Hat\u0131rlarsak hexagonal architecture i\u00e7in, merkezinde core&#8217;u bar\u0131nd\u0131ran ve istedi\u011fimiz adapter&#8217;\u00fc s\u00f6k\u00fcp takabilece\u011fimiz bir plug-in yap\u0131s\u0131 gibi d\u00fc\u015f\u00fcnebiliriz demi\u015ftik.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Implementasyon i\u00e7in \u00f6ncelikle a\u015fa\u011f\u0131daki komut sat\u0131r\u0131n\u0131 kullanarak, bir <em>ASP.NET Core<\/em> Emtpy Web projesi olu\u015ftural\u0131m.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<pre class=\"wp-block-code\"><code>dotnet new web -n Minimal.API<\/code><\/pre>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Ard\u0131ndan application domain layer&#8217;\u0131 ve infrastructure adapter&#8217;\u00fcn\u00fc referans olarak ekleyelim.<\/p>\r\n<pre class=\"lang:default decode:true\">dotnet add reference ..\/Minimal.Core\/Minimal.Core.csproj\r\ndotnet add reference ..\/Minimal.Infrastructure\/Minimal.Infrastructure.csproj<\/pre>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Application domain i\u00e7erisinde business use-case&#8217;lerini implemente ederken, <em>MediatR<\/em> library&#8217;sinden yararlanm\u0131\u015ft\u0131k. Bu yakla\u015f\u0131m sayesinde <em>API<\/em> ile application domain aras\u0131ndaki ileti\u015fimi, loosely coupled olarak tek bir noktadan ger\u00e7ekle\u015ftirebilece\u011fimizden bahsetmi\u015ftik.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Bunun i\u00e7in, <em>NuGet<\/em> \u00fczerinden &#8220;<em>MediatR<\/em>&#8221; ve &#8220;<em>MediatR.Extensions.Microsoft.DependencyInjection<\/em>&#8221; paket&#8217;lerini <em>API <\/em>projesine dahil etmemiz gerekmektedir.<\/p>\r\n<pre class=\"lang:default decode:true\">dotnet add package MediatR\r\ndotnet add package MediatR.Extensions.Microsoft.DependencyInjection<\/pre>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Art\u0131k implementasyon i\u015flemine haz\u0131r\u0131z.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u015eimdi &#8220;<em>Controllers<\/em>&#8221; klas\u00f6r\u00fc alt\u0131nda, &#8220;<code>MoviesController<\/code>&#8221; isminde bir <em>API <\/em>controller class&#8217;\u0131 olu\u015ftural\u0131m ve a\u015fa\u011f\u0131daki gibi kodlayal\u0131m.<\/p>\r\n<pre class=\"lang:default decode:true\">using System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing MediatR;\r\nusing Microsoft.AspNetCore.Mvc;\r\nusing Minimal.Core.Dtos;\r\nusing Minimal.Core.Dtos.Requests;\r\n\r\nnamespace Minimal.API.Controllers\r\n{\r\n    [Route(\"api\/[controller]\")]\r\n    [ApiController]\r\n    public class MoviesController : ControllerBase\r\n    {\r\n        private readonly IMediator _mediator;\r\n\r\n        public MoviesController(IMediator mediator)\r\n        {\r\n            _mediator = mediator;\r\n        }\r\n\r\n        [HttpPost]\r\n        public async Task&lt;ActionResult&lt;string&gt;&gt; CreateMovieAsync([FromBody]CreateMovieRequest createMovieRequest)\r\n        {\r\n            BaseResponseDto&lt;bool&gt; createResponse = await _mediator.Send(createMovieRequest);\r\n\r\n            if (createResponse.Data)\r\n            {\r\n                return Created(\"...\", null);\r\n            }\r\n            else\r\n            {\r\n                return BadRequest(createResponse.Errors);\r\n            }\r\n        }\r\n\r\n        [HttpGet(\"kids\")]\r\n        public async Task&lt;ActionResult&lt;List&lt;MovieDto&gt;&gt;&gt; GetBestMoviesForKidsAsync()\r\n        {\r\n            BaseResponseDto&lt;List&lt;MovieDto&gt;&gt; getBestMoviesForKidsReponse = await _mediator.Send(new GetBestMoviesForKidsRequest());\r\n\r\n            if (!getBestMoviesForKidsReponse.HasError)\r\n            {\r\n                return Ok(getBestMoviesForKidsReponse.Data);\r\n            }\r\n            else\r\n            {\r\n                return BadRequest(getBestMoviesForKidsReponse.Errors);\r\n            }\r\n        }\r\n    }\r\n}<\/pre>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Yukar\u0131daki kod blo\u011funda, movie olu\u015fturabilmek i\u00e7in gerekli olan &#8220;<code>CreateMovieAsync<\/code>&#8221; ve \u00e7ocuklar i\u00e7in en iyi filmleri getirecek olan &#8220;<code>GetBestMoviesForKidsAsync<\/code>&#8221; method&#8217;lar\u0131n\u0131 implemente ettik.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Method&#8217;lar i\u00e7erisinde ise mediator&#8217;a, sadece handle etmesini istedi\u011fimiz ilgili request model&#8217;lerini parametre olarak a\u015fa\u011f\u0131daki gibi set ettik.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<pre class=\"lang:default decode:true\">await _mediator.Send(createMovieRequest);\r\nawait _mediator.Send(new GetBestMoviesForKidsRequest());<\/pre>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Mediator ise burada, bizim i\u00e7in ilgili request handler&#8217;lar\u0131n\u0131 bulup, request modellerini execute edecektir. Bu i\u015flemleri tek bir noktadan ger\u00e7ekle\u015ftirebilmek, ne kadar da pratik bir yakla\u015f\u0131m de\u011fil mi?<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:image {\"id\":2987,\"width\":614,\"height\":387,\"sizeSlug\":\"large\"} --><\/p>\r\n<figure class=\"wp-block-image size-large is-resized\"><img decoding=\"async\" class=\"wp-image-2987 lazyload\" data-src=\"https:\/\/i0.wp.com\/gokhan-gokalp.com\/wp-content\/uploads\/2019\/12\/magic-mediatr.jpg?fit=1024%2C647&amp;ssl=1\" alt=\"\" width=\"614\" height=\"387\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2019\/12\/magic-mediatr.jpg 1424w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2019\/12\/magic-mediatr-300x190.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2019\/12\/magic-mediatr-1024x647.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2019\/12\/magic-mediatr-768x485.jpg 768w\" data-sizes=\"(max-width: 614px) 100vw, 614px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 614px; --smush-placeholder-aspect-ratio: 614\/387;\" \/><\/figure>\r\n<p><!-- \/wp:image --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u015eimdi &#8220;<code>Startup<\/code>&#8221; class&#8217;\u0131nda ise injection i\u015flemlerini a\u015fa\u011f\u0131daki gibi ger\u00e7ekle\u015ftirelim.<\/p>\r\n<pre class=\"lang:default decode:true\">using MediatR;\r\nusing Microsoft.AspNetCore.Builder;\r\nusing Microsoft.AspNetCore.Hosting;\r\nusing Microsoft.AspNetCore.Mvc;\r\nusing Microsoft.EntityFrameworkCore;\r\nusing Microsoft.Extensions.Configuration;\r\nusing Microsoft.Extensions.DependencyInjection;\r\nusing Minimal.Core.Interfaces;\r\nusing Minimal.Core.Services.MovieUseCases;\r\nusing Minimal.Infrastructure;\r\nusing Minimal.Infrastructure.Repositories;\r\nusing Swashbuckle.AspNetCore.Swagger;\r\n\r\nnamespace Minimal.API\r\n{\r\n    public class Startup\r\n    {\r\n        public Startup(IConfiguration configuration)\r\n        {\r\n            Configuration = configuration;\r\n        }\r\n\r\n        public IConfiguration Configuration { get; }\r\n\r\n        \/\/ This method gets called by the runtime. Use this method to add services to the container.\r\n        public void ConfigureServices(IServiceCollection services)\r\n        {\r\n            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);\r\n\r\n            \/\/Infrastructure\r\n            services.AddDbContext&lt;AppDbContext&gt;(opt =&gt; opt.UseInMemoryDatabase(\"TestDB\"));\r\n            services.AddScoped(typeof(IRepository&lt;&gt;), typeof(Repository&lt;&gt;));\r\n\r\n            \/\/Services\r\n            services.AddMediatR(typeof(CreateMovieHandler));\r\n        }\r\n\r\n        \/\/ This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\r\n        public void Configure(IApplicationBuilder app, IHostingEnvironment env)\r\n        {\r\n            if (env.IsDevelopment())\r\n            {\r\n                app.UseDeveloperExceptionPage();\r\n            }\r\n            else\r\n            {\r\n                \/\/ The default HSTS value is 30 days. You may want to change this for production scenarios, see https:\/\/aka.ms\/aspnetcore-hsts.\r\n                app.UseHsts();\r\n            }\r\n\r\n            app.UseMvc();\r\n        }\r\n    }\r\n}<\/pre>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:code --><\/p>\r\n<p><!-- \/wp:code --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>&#8220;<code>Startup<\/code>&#8221; class&#8217;\u0131 i\u00e7erisinde, test amac\u0131yla bir in-memory database kullanaca\u011f\u0131m\u0131z\u0131 belirttik. Ard\u0131ndan &#8220;<code>IRepository<\/code>&#8221; interface&#8217;inin ve <em>MediatR<\/em> library&#8217;sinin injection i\u015flemlerini ger\u00e7ekle\u015ftirdik.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Art\u0131k bu adapter de haz\u0131r durumda.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>B\u00f6ylece bu \u00f6rnek projenin, <strong>clean architecture<\/strong> ile implementasyonunu tamamlad\u0131k diyebiliriz.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:heading --><\/p>\r\n<h2>Sonu\u00e7<\/h2>\r\n<p><!-- \/wp:heading --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u00d6zellikle yukar\u0131dan a\u015fa\u011f\u0131ya do\u011fru bir dependency flow&#8217;una al\u0131\u015fm\u0131\u015fsak, port&#8217;lar\u0131 yani interface&#8217;leri application domain i\u00e7erisinde tan\u0131mlay\u0131p, ard\u0131ndan adapter&#8217;lerini architecture&#8217;\u0131n etraf\u0131nda implemente etmek biraz garip gelebilir. Architecture&#8217;a al\u0131\u015ft\u0131ktan sonra ise, bu yakla\u015f\u0131m\u0131n, gelebilecek olan de\u011fi\u015fimler\/yeni \u00f6zellikler, test edilebilirlik ve maintenance i\u015flemleri kar\u015f\u0131s\u0131nda bizlere nas\u0131l h\u0131z ve esneklik kazand\u0131rd\u0131\u011f\u0131n\u0131 g\u00f6rebiliriz.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u00d6rne\u011fin, database olarak bir <em>NoSQL<\/em> teknolojisi kullanmaya karar verdi\u011fimizi varsayal\u0131m. Tek yapmam\u0131z gereken &#8220;<code>IRepository<\/code>&#8221; port&#8217;unu implemente eden bir adapter olu\u015fturmak ve gerekli injection i\u015flemlerini ger\u00e7ekle\u015ftirmek.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>\u00c7\u00fcnk\u00fc architecture&#8217;\u0131n do\u011fas\u0131 gere\u011fi d\u0131\u015f d\u00fcnya ile hi\u00e7 bir ba\u011f\u0131ml\u0131l\u0131\u011f\u0131 bulunmayan bir inner\/core layer in\u015faa ediyoruz.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:image {\"id\":3004,\"sizeSlug\":\"large\"} --><\/p>\r\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1027\" height=\"572\" class=\"wp-image-3004 lazyload\" data-src=\"https:\/\/i1.wp.com\/gokhan-gokalp.com\/wp-content\/uploads\/2019\/12\/clean-architecture-adapters.jpg?fit=1024%2C570&amp;ssl=1\" alt=\"\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2019\/12\/clean-architecture-adapters.jpg 1027w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2019\/12\/clean-architecture-adapters-300x167.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2019\/12\/clean-architecture-adapters-1024x570.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2019\/12\/clean-architecture-adapters-768x428.jpg 768w\" data-sizes=\"(max-width: 1027px) 100vw, 1027px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1027px; --smush-placeholder-aspect-ratio: 1027\/572;\" \/><\/figure>\r\n<p><!-- \/wp:image --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p>Core layer&#8217;\u0131n etraf\u0131n\u0131 ise, ihtiya\u00e7lar do\u011frultusunda <strong>de\u011fi\u015ftirilebilir<\/strong> adapter&#8217;ler ile donat\u0131yoruz.<\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p><!-- wp:paragraph --><\/p>\r\n<p><em><a href=\"https:\/\/github.com\/GokGokalp\/CleanArchitectureBoilerplates\/tree\/master\/src\/MinimalCleanArchitecture\">https:\/\/github.com\/GokGokalp\/CleanArchitectureBoilerplates\/tree\/master\/src\/MinimalCleanArchitecture<\/a><\/em><\/p>\r\n<p><!-- \/wp:paragraph --><\/p>\r\n<p>","protected":false},"excerpt":{"rendered":"<p>Hen\u00fcz makalenin ilk b\u00f6l\u00fcm\u00fcn\u00fc okumad\u0131ysan\u0131z, konuyu daha iyi anlayabilmek ad\u0131na buradan ula\u015fabilirsiniz. Makalenin bu ikinci b\u00f6l\u00fcm\u00fcnde ise, clean architecture konsept&#8217;inin .NET Core ile minimal d\u00fczeyde implementasyon i\u015fleminden bahsedece\u011fim. \u00d6rnek olarak, i\u00e7erisinde film ekleyebilece\u011fimiz ve listeleyebilece\u011fimiz basit bir API geli\u015ftirece\u011fiz. Application Domain&#8217;in Implementasyonu \u0130lk \u00f6nce architecture&#8217;\u0131n&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/gokhan-gokalp.com\/tr\/getting-started-with-clean-architecture-using-asp-net-core-02\/\">Devam\u0131n\u0131 okuyun<span class=\"screen-reader-text\">Getting Started with Clean Architecture using ASP.NET Core \u2013 02<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":2919,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[505,68,417],"tags":[526,419,543,548,544],"class_list":["post-2918","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-core","category-architectural","category-asp-net-core","tag-net-core","tag-asp-net-core","tag-clean-architecture","tag-dotnet-core","tag-hexagonal-architecture","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"tr","enabled_languages":["en","tr"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"tr":{"title":true,"content":true,"excerpt":false}}},"_links":{"self":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/2918","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/comments?post=2918"}],"version-history":[{"count":5,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/2918\/revisions"}],"predecessor-version":[{"id":3048,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/2918\/revisions\/3048"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/media\/2919"}],"wp:attachment":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/media?parent=2918"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/categories?post=2918"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/tags?post=2918"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}