View on GitHub

OnionArchitecture

مفاهیم معماری OnionArchitecture و کاربرد آن در Asp.net Core

# Onion Architecture یا معماری پیاز در این مخزن کلیه های مفاهیم مرتبط با معماری پیاز توضیح داده می شود و در نهایت با asp.net Core تمامی مفاهیم با کد بیان می شوند تا به صورت کامل با این معماری و مفاهیم آن آشنا شوید و بتوانید از این معماری قدرتمند در برنامه های خود بهره ببرید. سرفصل های مورد پوشش : + [معرفی](#header1) + [Tight Coupling](#header1) + [Loose Coupling](#header2) + [مزایای معماری Onion](#header3) + [چرا باید از معماری onion استفاده کنیم؟](#header4) + [ساختار برنامه ها در معماری onion](#header5) + [مزایای معماری Onion](#header6) + [مزایای معماری Onion](#header7) + [مزایای معماری Onion](#header8) ___
# معرفی
معماری OnionArchitecture در سال 2018 توسط JeffreyPalermo ابداع شد. این معماری روشی بهتر جهت تولید برنامه های با قابلیت تست و نگه داری و قابلیت اطمینان در زیر ساخت های برنامه مانند بانک ها و سرویس ها ارائه می دهد.هدف نهایی این معماری مقابله و رفع مشکلات و چالش های معماری های 3 لایه و n لایه و ارائه راه حل هایی برای مشکلات معمول مانند جفت شدگی یا coupling و جداسازی دغدغه ها یا separation of concerns است. در حال حاضر دو نوع جفت شدگی یا Coupling داریم : tight coupling و loose coupling
# Tight Coupling
وقتی یک کلاس دارای وابستگی شدید است گفته می شود که آن کلاس دارای جفت شدگی محکم یا Tight Coupling است. یک شی جهت شده محکم به یک شی دیگر وابسته است به گونه ای که تغییر در یک کلاس لازمه تغییر در اشیا دیگر را دارد. این مورد برای برنامه های کوچک مشکلی ایجاد نمی کند اما این تغییرات برای برنامه های حرفه ای سخت است.
# Loose Coupling
این به این معنا است که دو شی غیر وابسته هستند و یک شی می تواند از یک شی دیگر استفاده کند بدون واسبتگی به آن. هدف نهایی این نوع طراحی کم کردن روابط داخلی بین اشیا و کامپوننت ها در یک سیستم و کاهش خطر اینکه تغییر در یک شی لازمه تغییرات در اشیا دیگر را داشته باشد.
# مزایای معماری Onion
مزایای زیادی برای آن عنوان شده است که شامل : 1. ارائه نگه داری بهتر به گونه ای که کل کد به لایه ها و مرکز وابسته باشند. 2. ارائه روشی بهتر برای تست به گونه ای که بتوان برای لایه های گوناگون تست هایی بدون .تاثیر بر ماژول های دیگر ایجاد کرد 3. ساخت برنامه ای با جفت شدگی شل به گونه ای که لایه های خارجی برنامه همیشه از طریق رابط ها یا interface ها با لایه های داخلی ارتباط برقرار کنند. 4. هر گونه القاء واقعی باید در برنامه باید در زمان اجرا ارائه شود 5. موجودیت های دامنه جز اصلی و هسته ای هستند که به لایه های دیتابیس و ui دسترسی دارند. 6. لایه های داخلی به لایه های خارجی وابستگی ندارند و هر کدی که احتمال تغییر دارد باید در لایه خارجی قرار بگیرد.
# چرا باید از معماری onion استفاده کنیم؟
تاکنون معماری های سنتی گوناگونی مانند 3 لایه و n لایه معرفی شده اند که هر کدام مزایا و معایب خود را دارند.تمامی این معماری های سنتی یک سری مشکلات پایه ای دارند مانند جفت شدگی محکم یا tight coupling و جداسازی دغدغه ها یا seperation of concern. معماری mvc عموما در معماری برنامه های وب مورد استفاده قرار می گیرد که مشکل جداسازی وابستگی ها حل می کند به گونه ای که لایه ارتباطی کاربر و تجاری و دیتا از هم تفکیک می کند. View برای طراحی رابط کاربری ، Model داده ها فراهم شده از لایه تجاری را بین View و Controller انتقال میدهد. controller مورد استفاده قرار می گیرد تا درخواست های وب را با action method ها مدیریت کند و ویو مناسب را برگرداند. این معماری مشکل جداسازی دغدغه ها به خوبی انجام می دهد در حالی که controller همجنان برای دسترسی به دیتابیس مورد استفاده قرار می گیرد.MVC ذاتا مشکل separation of concern را حل می کند اما همچنان مشکل جفت شدگی .اما معماری onion هر دو مشکل جداسازی دغدغه ها و جفت شدگی سخت را حل می کند . خلاصه فلسفه این معماری نگه داری منطق تجاری و دیتا و مدل در مرکز برنامه و ارسال وابستگی ها به خارج از آن ها و تا حد ممکن در مرکز.
# لایه های معماری onion
این معماری واسبتگی شدیدی به اصل Dependency Inversion دارد. رابط کاربری با لایه تجاری از طریق رابط ها interface ها ارتباط برقرار می کند. این معماری شامل 4 لایه است . 1. Domain Entites 2. Repository 3. Service 4. UI(Web/Unit Test) ![Onion Architecture Layers][1] این لایه ها به سمت مرکز حرکت می کنند . بخش داخلی Domain Entities است که اشیای تجاری و رفتاری را ارائه می دهد.این لایه ها می توانند متفاوت باشند اما domain entitis همیشه در مرکز است و لایه های دیگر رفتار های یک شی را بیان می کنند. ## 1.Domain Entities Layer در مرکز معماری قرار دارد. کلیه ی اشیا برنامه را نگه داری می کند.اگر برنامه با orm هایی مانند Entity framework توسعه داده شده باشد بنابرین این لایه می تواند شامل POCO کلاس ها در طراحی Code First یا Edmx در طراحی Database First با entity ها یا موجودیت ها باشد.این موجودیت ها هیچ وابستگی نداند. ## 2. Repository Layer این لایه با هدف ایجاد یک لایه انتزاعی بین موجودیت های لایه دامنه و منطق لایه تجاری در یک برنامه ایجاد می شود. این لایه یک الگوی دسترسی به دیتا دارد که تلاش می کند که جفت شدگی کمتری در دسترسی به دیتا ایجاد کند.در این لایه یک Generic Repository ایجاد می شود که منبع داده ای را برای داده ها جستجو می کند و داد ه ها را با موجودیت های تجاری ارتباط می دهد و همواره تغییرات را میان موجودیت های تجاری و منبع داده حفظ می کند. ## 3. Service Layer این لایه رابط ها یا interface ها برای ارتباط بین لایه کاربری و repository را شامل می شود.این لایه منطق تجاری برای یک موجودیت نگه داری می کند و به همین خاطر به آن لایه منطق تجاری نیز گفته می شود. ## 4. UI Layer این لایه خارجی ترین لایه است. این لایه همان Web Application , Web API یا Unit Test است. این لایه اصل وارونه سازی وابستگی ها را پیاده سازی می کند بنابرین برنامه هایی با جفت شدگی شل ایجاد می کند و ارتباط آن با لایه های داخلی تنها با رابط ها یا Interface ها است.
# ساختار برنامه ها در معماری onion
جهت پیاده سازی معماری onion از Asp.net Core استفاه شده است و عملیات CRUD را بر روی موجودیت ها نشان می دهد. ![Application projects structure][2] در این پروژه 3 کتابخانه کلاس و یک برنامه وب وجود دارد که ارتباط هر کدام با معماری پیاز را توضیح می دهیم. ## 1. OA.Data یک کتابخانه کلاس است که شامل کلاس های POCO و نشان دهنده ی لایه دامنه موجودیت ها یا Domain Entities معماری پیاز است.این کلاس ها در حقیقت برای ساخت جداول دیتابیس استفاده می شوند و بخش مرکزی برنامه است. ## 2. OA.Repo کتابخانه کلاس دوم شامل یک Generic Repository کلاس و پیاده سازی رابط ها یا interface ها و کلاس DbContext است. Entity FrameWork با الگوی Code First برای دسترسی به داده ها یک کلاس context از Dbcontext ارث بری میکند. ## 3.OA.Service کتابخانه کلاس سوم نگه دارنده منطق تجاری و رابط ها است.این رابط ها ارتباط بین لایه رابط کاربری و منطق دسترسی دیتا را برقرار می کنند.از آنجایی که از طریق رابط ها ارتباط برقرار می کنند برنامه هایی با جفت شدگی شل ایجاد می کنند. این پروژه نشان دهنده لایه Repository در معماری پیاز است. ## 4. OA.Web این پروژه Asp.net Core است که برای ساخت تست های واحد یا Web Api ها مورد استفاده قرار می گیرد.خارجی ترین لایه است که برای تعامل کاربر با برنامه استفاده می شود و با استفاده از اصل وارونه سازی وابستگی ها برنامه هایی با جفت شدگی شل ایجاد می کند و معادل لایه UI در معماری پیاز است. # پیاده سازی معماری پیاز برای پیاده سازی معماری پیاز این 4 پروژه را ایجاد کنید که نشان دهنده 4 لایه معماری پیاز هستند. # Domain Entities Layer Domain Entities بخش مرکزی و در اصل هسته معماری پیاز است.بنابرین پروژه OA.Data را ایجاد می کنیم تا این لایه را پیاده سازی کنیم. این پروژه برای نگه داری کلاس های POCO است.در این لایه 3 موجودیت تعریف شده است که از یک کلاس پایه به نام BaseEntity دارد و پراپرتی های آن را ارث بری می کنند.

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Threading.Tasks;  
  
namespace OA.Data  
{  
    public class BaseEntity  
    {  
        public Int64 Id { get; set; }  
        public DateTime AddedDate { get; set; }  
        public DateTime ModifiedDate { get; set; }  
        public string IPAddress { get; set; }  
    }  
}  

همچنین شامل دو موجودیت دیگه به نام User و UserProfile است که هر دو از BaseEntity ارث بری می کنند.

One to One User-UserProfile relationship


namespace OA.Data  
{  
    public class User:BaseEntity  
    {  
        public string UserName { get; set; }  
        public string Email { get; set; }  
        public string Password { get; set; }  
        public virtual UserProfile UserProfile { get; set; }  
    }  
}  


using Microsoft.EntityFrameworkCore.Metadata.Builders;  
  
namespace OA.Data  
{  
    public class UserMap  
    {  
        public UserMap(EntityTypeBuilder<User> entityBuilder)  
        {  
            entityBuilder.HasKey(t => t.Id);  
            entityBuilder.Property(t => t.Email).IsRequired();  
            entityBuilder.Property(t => t.Password).IsRequired();  
            entityBuilder.Property(t => t.Email).IsRequired();  
            entityBuilder.HasOne(t => t.UserProfile).WithOne(u => u.User).HasForeignKey<UserProfile>(x => x.Id);  
        }  
    }  
}  


namespace OA.Data  
{  
    public class UserProfile:BaseEntity  
    {  
        public string FirstName { get; set; }  
        public string LastName { get; set; }  
        public string Address { get; set; }  
        public virtual User User { get; set; }  
    }  
}  


using Microsoft.EntityFrameworkCore.Metadata.Builders;  
  
namespace OA.Data  
{  
    public class UserProfileMap  
    {  
        public UserProfileMap(EntityTypeBuilder<UserProfile> entityBuilder)  
        {  
            entityBuilder.HasKey(t => t.Id);  
            entityBuilder.Property(t => t.FirstName).IsRequired();  
            entityBuilder.Property(t => t.LastName).IsRequired();  
            entityBuilder.Property(t => t.Address);    
        }  
    }  
}  

لینک اصلی محتوا Onion Architecture

</div>