آشنایی با معماری پیاز (Onion Architecture) و تکنولوژی Database First در MVC

هدف اصلی از این مقاله , آشنایی با معماری پیاز در MVC با استفاده از تکنولوژی DataBase First میباشد .همچنین در مثال ارائه شده , شامل کد نمونه میباشد که شما را در درک بیشتر این معماری یاری می رساند .

آشنایی با معماری پیاز (Onion Architecture) و تکنولوژی Database First در MVC

در این مقاله به مفاهیم زیر اشاره شده است :

- تولید یک پروژه MVC با استفاده از معماری پیاز

- تکنولوژی Entity Framework با استفاده از روش Database First

- تزریق وابستگی (Dependency injection) با استفاده از Unity Container

- الگوی Repository به همراه یک repository برای هر شئی

آموزش کامل و پروژه محور معماری پیاز در mvc را در تاپ لرن میتوانید مشاهده کنید .

معماری پیاز چیست ؟

این معماری توسط Jeffrey Palermo  در سال 2008 ابداع شد .مدت ها پیش این معماری به یک تکنولوژی محبوب شد .هنگامی که شما به جزئیات این معمار آگاه شوید , ممکن است احساس کنید که آماده استفاده از این تکنولوژی شده اید .

به عنوان معرفی کوتاه , معماری پیاز یک روش برای طراحی لایه های نرم افزار شما میباشد همانند لایه های پیاز .درونی ترین لایه یا به عبارتی دیگر هسته نرم افزار , نسبت به لایه های بیرونی خود مستقل است و هیچ وابستگیی با لایه های بیرونی ندارد .همینطور که از هسته به سمت لایه های بیرونی حرکت می کنیم , هر لایه به لایه داخلی خود وابستگی دارد , اما نسبت به لایه بیرونی خود هیچگونه وابستگی ندارد .به عنوان مثال اگر نرم افزار ما شامل 3 لایه باشد , لایه اول که درونی ترین لایه یا همان هسته نرم افزار است .سپس لایه دوم قرار دارد و پس از آن لایه سوم است که خارجی ترین لایه موجود در نرم افزار است .بنابراین برای اعمال معماری پیاز در این نرم افزار باید لایه اول را مستقل از دو لایه دیگر قرار دهیم , سپس لایه دوم را در قسمت بعدی هسته (لایه اول) قرار دهیم که این لایه فقط به هسته وابسته میباشد و در آخر لایه سوم میباشد که به لایه دوم و هسته وابسته میباشد .

بنابراین مهمترین نکته در معماری پیاز این است که هر اندازه که ما از هسته به سمت لایه های بیرونی حرکت میکنیم , وابستگی لایه ها نیز بیشتر میشوند .معماری نرم افزار , باید مشابه تصویر زیر باشد :

اکنون برای ایجاد یک پروژه MVC , ویژوال استودیو را اجرا میکنیم , از پنجره باز شده گزینه Asp.Net MVC 5 Empty Project را انتخاب میکنیم .

در ادامه در قسمت مدل برخی جدول را از بانک اطلاعاتی دریافت میکنیم .برای این کار از روش Entity Framework database first استفاده میکنیم . بنابراین باید edmx. را که پسوند مدل میباشد را باید به پروژه اضافه کنیم .لازک به ذکر است که از کتابخانه کلاس ها edms. را با نام SampleArtchitecture.Infrastructure اضافه میکنیم .

در ادامه برای نمایش مقادیر اطلاعات موجود در جدول , ما کلاس UsersRepository.cs را فراخوانی میکنیم .مانند همه پروژه ها  , متد های CRUD که شامل Create , Update و Delete میباشد را اضافه میکنیم .در این پروژه همچنین متد GetAllUsers را که برای دریافت تمامی اطلاعات مربوط به جدول کاربران میباشد , را فراخوانیم می کنیم .

اکنون controller ها را به پروژه اضافه میکنیم . سپس view مربوط به هر controller را نیز اضافه میکنیم .متد repository GetAllUsers را نیز فراخوانی می کنیم .برای دستیابی به repository , ما باید refrence را به ساختار پروژه اضافه کنیم .

Model را به View متصل میکنیم و پروژه را اجرا میکنیم .

در یک نگاه این نرم افزار مشکل و کمبودی ندارد .اما اگر با دقت بیشتری نرم افزار را بررسی کنیم , به تعدادی مشکلی مواجه میشویم که در ادامه به آنها اشاره می کنیم :

1 - نقض قانون Single Responsibility : کلاس های کنترلر به کلاس UserRepository وابستگی دارد .موضوع این است که متد Controller مسئول وظایف چندگانه میباشد .به عبارت دیگز معرفی repository و نمایش اطلاعات به همراه View است .در اینجا نقض قانون SOLID است که به این معنی میباشد که هر کلاس  یا تابع فقط مسئول یک وظیفه(task) میباشد .

2 - فشردگی (Tight Coupling) بین وب و ساختار پروژه : پروژه ما مستقیما به entity وابستگی دارد .این امر نه تنها در مورد Controller ها صدق میکند , بلکه مربوط به view ها(در مورد View از زمانی وابستگی پدید می آید که view از خاصیت اتصال به Model استفاده می کند ) نیز میباشد .
 بنابراین در آینده با توجه به برخی از دلیل ها ما باید استفاده از EntityFrameWork را حذف کنیم .این عمل نه تنها بر روی ساختار پروژه تاثیر گذار است , بلکه هنگامی که نرم افزار مستقیما به entities در Controller و View اشاره میکند نیز موثر می باشد .

3 - کلاس فشرده Repository : در پروژه ما کلاس فشرده UserRepository وجود دارد که در صورت استفاده از آن فشردگی اجزاء را افزایش می دهد .

بنابراین باید فشردگی و پیچیدگی با استفاده از Entity Framework به همراه Controller و View  کاهش دهیم .بنابراین میتوانیم از کلاس POCO استفاده کنیم که اطلاعات را از بانک اطلاعاتی در خود حمل میکند . از repository , Controller و سپس در آخر از View استفاده میکند .نکته بسیار مهم این است که کلاس POCO را در کدام قسمت اضافه کنیم .ما میتوانیم در ساختار پروژه این کلاسها را اضافه کنیم .اما نکته اینجاست که این کلاسها تنها برای اتصال به بانک اطلاعاتی میباشد , پس چرا آنها را در لایه مستقل قرار ندهیم؟

1 - هسته مرکزی میتواند از ساختار پروژه مستقل باشد .

2 - لایه های ساختار پروژه از لایه های وب مستقل میباشند .اما به هسته وابسته میباشند .

3 - لایه های وب نیز به هر دو لایه قبل (لایه هسته و لایه ساختار ) وابسته میباشد .

یک پروژه جدید از کتابخانه کلاسها ایجاد میکنیم و کلاس POCO را اضافه می کنیم .یکی دیگر از مزایای این کلاسها این است که ما میتوانیم اعتبارسنجی را نیز به پروژه اضافه کنیم .

مرحله بعدی متد Repository را برای استفاده از کلاس POCO  , تغییر می دهیم

سپس نرم افزار را اجرا میکنیم .و میتوانید نتیجه را مشاهده کنید .

اکنون اگر شما احتیاج به حذف Entity Framework داشته باشید , شما باید لایه ساختار را تغییر دهید و هیچ احتیاجی به تغییر متد Controller و یا View نمی باشد .

سپس باید refrence مربوط به Unity DLL را با استفاده از Nuget Package اضافه کنید .

یک interface با نام IUserRepository اضافه میکنیم . این interface را در کلاس UserRepository اجرا میکنیم .مانند قبل این سؤال مطرح میشود که interface را در کدام قسمت اضافه کنیم ؟ پس باید interfacee را در یک پروژه مجزا ایجاد کنیم .

در مثال موجود , ما به UserRepository instance احتیاج داریم .بنابراین Unity Container این عمل را برای ما انجام میدهد .اما قبل از انجام آن , ما باید نیازها و وابستگیهای خود را ثبت کنیم . ثبت وابستگی مشابه این عمل میباشد که به Container اطلاع دهید , زمانی که از interface استفاده میکنیم . این instance را در اختیار ما قرار بده .در زمان اجرا وابستگی را از  بررسی می کند و به متدی که احتیاج دارد تزریق میکند .

کلاسی با نام UnityContainerRegistration را اضافه می کنیم و سپس وابستگی این کلاس را نیز ثبت میکنیم .این کلاس را به پروژه وب سایت اصلی خود اضافه میکنیم .

container را در فایل Global.asax قرار می دهیم .هنگامی که نرم افزار اجرا شد , تمام وابستگی ها ثبت میشوند .

در آخر Controller خود را برای دریافت وابستگی از UserRepository تغییر میدهیم . این وابستگی با استفاده از Unity container و ثبت آن که در بالا اشاره شد , انجام  میشود .

اکنون پروژه را اجرا می کنیم و هیچ تاثیری در نتیجه برنامه ندارد .اما در قسمت کد این برنامه , وابستگی ها همانطور که ما به انها اشاره کردیم , ایجاد شد .به معنی دیگر SampleArchtecture.Core که لایه داخلی یا همان هسته میباشد .پروژه SampleArchitecture.infrastructure که به هسته وابسته میباشد , لایه بیرونی میباشد و لایه وب که آخزین لایه  میباشد و به هر دو لایه ذکر شده وابستگی دارد .