جواد جهانگیری
جواد جهانگیری
خواندن ۹ دقیقه·۳ سال پیش

الگوی UnitOfWork pattern در C# asp.net core

به نام آن که جان را فکرت آموخت / چراغ دل به نور جان برافروخت

با عرض سلام و وقت بخیر خدمت کاربران محترم سایت ویرگول، در این مقاله آموزشی به موضوع نحوه ساخت و استفاده از الگوی Repository و Generic Repository به همراه Unit Of Work پرداخته می شود و سعی شده یک آموزش کاربردی و پروژه محور از بحث Unit Of Work ارایه گردد.ایده این سری مقاله های آموزشی از این موضوع سرچشمه می گیرد که بخشی از خوانندگان وجود دارد که به محتوای نوشتاری آنلاین بهتر پاسخ می دهند و ترجیج می دهند مهارت های جدید را به سرعت از طریق خواندن افزایش دهند.این سری اموزش ها با ارایه پکیج آموزش های کاربردی در خصوص C# asp.net core آغاز می شود که انتظار می رود با واکنش مثبت کاربران همراه شود.

https://www.aparat.com/javadjahangiriniopdc/playlists
توجه: این مقاله به مرور زمان، ویرایش و یا تکمیل می‌شود!
تقاضا: در صورتی که با مشکل تایپی، دستوری و یا مفهومی در این مقاله برخورد کردید، از شما دوست عزیز و گرامی، صمیمانه تقاضا می‌کنم که اینجانب را مطلع کرده، تا نسبت به تصحیح و یا تکمیل آن، در اسرع وقت، اقدام نمایم.
با کمال تشکر
جواد جهانگیری
شماره تلفن همراه: 09149431772
نشانی پست الکترونیکی: javad.jahangiri.niopdc@gmail.com
فیلم‌های آموزشی در آپارات:جواد جهانگیری (CTO) - آپارات
فیلم آموزشی در یوتویب: javad jahangiri - YouTube
نسخه مقاله: ۱.۱ - تاریخ بروزرسانی: 1400/09/09

فرض کنید وقتی یک درخواست به روی سرور ارسال می شود باعنایت اینکه چندین کلاس و یا تابع برای پاسخ به این درخواست فراخوانی شود و از سوی دیگر ممکن است از هر کدام از انها به DbContext و داده های خود نیاز داشته باشد ،بعبارتی یک درخواست برای اجرا نیاز به چندین نمونه از DbContext را نیاز داشته باشد ما باید کاری کنیم و مکانیزمی تعریف کنیم که در یک Request فقط و فقط یک نمونه از DbContext ایجاد شود.این به این مفهوم نیست که ما یک کانکشن برای کل برنامه Application ایجاد کنیم (SingleTone) این کار درستی نیست بلکه ما می خواهیم به ازای Per Request فقط یک نمونه ازDbContext را داشته باشیم

توجه:در برنامه های ویندوز فرم دانت ما حالت Stateful را داریم و کانکشن تو حافظه کاربر ایجاد می شود و مشکلی ندارد به ازای کل Application ما یک کانکشن داشته باشیم و حتی Performance را نیز افزایش می دهد ولی برنامه های وب بصورت Stateless می باشد و بعد از این که یک درخواست اجرا می شود کل اطلاعات از روی سرور حذف می شود اگر به ازای کل برنامه یک کانکشن داشته باشیم یعنی Singleton به ازای Application باشد با ورود اولین کاربر یک کانکشن ایجاد می شود و با بیرون رفتن کاربر این کانکشن بسته شده و تمامی درخواست های سایر کاربران با خطا مواجه می شود پس باید کاری کنیم که به ازای هر درخواست حالت Singleton را داشته باشیم

توجه شود Unit of Work (UOW)بصورت توکار در داخل Entity Framework موجود است

Unit of Work به معنای واحد کار است و یک نوع الگوی طراحی است. بر اساس این الگو نباید در هر قسمت از برنامه شئ ای از روی DbContext بسازیم و فقط یک بار باید از روی DbContext شی جدید ساخت. به عبارت دیگر برنامه نویس در لایه ی Business Logic نباید با Repository های مختلف کار کند و این وظایف باید به Unit of Work سپرده شود و برنامه نویس فقط از آن استفاده کند. می توان از Unit of Work به عنوان یک Facade از Repository ها یاد کرد.

طبق این الگو، تمام درخواست های کار با دیتابیس در یک صف قرار می گیرند و پشت سر هم انجام می شوند. بعد از آنکه تمام این درخواست ها با موفقیت اجرا شدند، دستور SaveChanges اجرا می شود. چون این الگوی طراحی از مفهوم Transaction استفاده می کند، اگر در این بین مشکلی پیش بیاید یا یکی از درخواست ها با خطا مواجه شود تمام درخواست ها لغو می شوند و هیچ تغییری در دیتابیس رخ نخواهد داد و در اصطلاح Rollback اتفاق می افتد.

این روش مزیت های بسیاری دارد، مثلا Connection های کمتری به دیتابیس وجود خواهند داشت چون در Unit of Work یک تراکنش به ازای چند عمل وجود دارد و نه یک تراکنش به ازای هر عمل.

چرا Unit Of Work ؟

  1. عدم دسترسی مستقیم Controller به دیتابیس هنگام عملیات CRUD. چون ارتباط، با استفاده از کلاس و اینترفیس مربوط به Unit Of Work برقرار می شود.
  2. افزایش امنیت دیتابیس
  3. بهینگی سیستم و جلوگیری از خطاهای بالقوه دیتابیسی( اگر درخواستی نیاز به چندین بار ارتباط با دیتابیس داشته باشد، در هر ارتباط یک نمونه از دیتابیس در سرور ساخته می شود که اگر تعداد درخواست ها بالا باشد سرعت دیتابیس و سرور کند می شود.)


طبق اموزش های ارایه شده در سایت مایکروسافت یه پروژه ASP.NET Core MVC به شرح ذیل ایجاد می کنیم:

https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/start-mvc?view=aspnetcore-5.0&tabs=visual-studio

یک پروژه از نوع C# asp.net Core Web App (Model-View-Controller) ایجاد می کنیم

یک نام دلخواه برای پروژه خود انتخاب کنید:

فریم ورک مورد نظر را انتخاب می کنیم در حال حاضر نسخه 6 مورد استفاده قرار می گیرد

در نهایت یک پروژه به شرح ذیل ایجاد می شود


ابتدا نسبت به نصب پکیج های مطابق شکل زیر اقدام می کنیم

Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.Design Microsoft.EntityFrameworkCore.SqlServer Microsoft.EntityFrameworkCore.Tools

یک Entity بنام Student به پروژه اضافه می کنید:

namespace UnitOfWorkWebApp.Models { public class Student { public int Id { get; set; } public string Name { get; set; } } }

ودر ادامه یک پوشه به پروژه infrastructure اضافه کرده ویک اینترفیس بنام IStudentRepo به شرح ذیل به پروژه اضافه می کنیم :

using UnitOfWorkWebApp.Models; namespace UnitOfWorkWebApp.infrastructure { public interface IStudentRepo { IList<Student> GetAll(); Student GetById(int id); void Insert(Student student); void Update(Student student); void Delete(Student student); } }

یک پوشه Data به پروژه اضافه کرده و یک کلاس تحت عنوان Context به پروژه اضافه می کنیم:

using Microsoft.EntityFrameworkCore; using UnitOfWorkWebApp.Models; namespace UnitOfWorkWebApp.Data { public class Context : DbContext { public Context(DbContextOptions options) : base(options) { } public DbSet<Student> Students { get; set; } } }

یک پوشه هم بنام Services به پروژه اضافه کنید و یک کلاس بنام StudentRepo به این پوشه اضافه کنید

using UnitOfWorkWebApp.Data; using UnitOfWorkWebApp.infrastructure; using UnitOfWorkWebApp.Models; namespace UnitOfWorkWebApp.Services { public class StudentRepo : IStudentRepo { private Context _context; public StudentRepo(Context context) { _context = context; } public void Delete(Student student) { _context.Students.Remove(student); } public IList<Student> GetAll() { return _context.Students.ToList(); } public Student GetById(int id) { var student = _context.Students.Where(x => x.Id == id).FirstOrDefault(); return student; } public void Insert(Student student) { _context.Students.Add(student); } public void Update(Student student) { _context.Students.Update(student); } } }


به پوشه infrastructure یک اینترفیس IUnitOfWork اضافه می کنیم:

namespace UnitOfWorkWebApp.infrastructure { public interface IUnitOfWork { IStudentRepo StudentRepo { get; } void Save(); } }

کلاس UnitOfWork به پوشه سرویس بصورت زیر اضافه می کنیم:

using UnitOfWorkWebApp.Data; using UnitOfWorkWebApp.infrastructure; namespace UnitOfWorkWebApp.Services { public class UnitOfWork : IUnitOfWork { private Context _context; private IStudentRepo _studentRepo; public UnitOfWork(Context context) { _context = context; } public IStudentRepo StudentRepo { get { return _studentRepo=_studentRepo ?? new StudentRepo(_context); } } public void Save() { _context.SaveChanges(); } } }


یک ConnectionStrings به فایل appsettings.json اضافه می کنیم:

{ &quotConnectionStrings&quot: { &quotDefaultConnection&quot: &quotServer=.;Database=UnitOfWork;Trusted_Connection=True;MultipleActiveResultSet=True&quot }, &quotLogging&quot: { &quotLogLevel&quot: { &quotDefault&quot: &quotInformation&quot, &quotMicrosoft.AspNetCore&quot: &quotWarning&quot } }, &quotAllowedHosts&quot: &quot*&quot }

همانگونه که در مستندات مایکروسافت هم ذکر شده است در نسخه دانت کور6 فایل startup حذف شده و باید کارهای مربوط به سرویس ها و تزریق وابستگی ها و MiddleWare را باید در فایل Program در قسمت مربوطه انجام داد
builder.Services.AddDbContext<Context>(options => options.UseSqlServer(builder.Configuration.GetConnectionString(&quotDefaultConnection&quot))); builder.Services.AddTransient<IUnitOfWork, UnitOfWork>();

در ادامه یک مایگریشن برای پروژه به شرح زیر ایجاد می کنیم:

Add-Migration first update-database


ساختار پروژه تا اینجای مقاله به شرح زیر می باشد

و دیتابیس بصورت زیر ساخته می شود


بصورت زیر توسط تابع سازنده unitofwork را به داخل کنترلر Home تزریق می کنیم:

حالا بصورت زیر می توانیم از UnitOfWork در کنترلر استفاده کنیم

با تشکر از مطالعه این مقاله ,مثل همیشه کنجکاو باشید!!!

در دوره های آموزش تضمینی مجتمع فنی ارومیه که به صورت خصوصی و عمومی در دو شیوه حضوری و آنلاین برگزار می شود سرفصل های بسیار متنوع و کاربردی را بصورت پروژه محور آموزش داده می شود تا شخص کارآموز بتواند بلافاصله پس از اتمام این دوره در کمترین زمان ممکن وارد بازار کار شود.
آموزش تخصص ماست با ما حرفه ای شوید
جهت مشاوره با شماره 09149431772 در ارتباط باشید ...


https://www.aparat.com/javadjahangiriniopdc/playlists


جواد جهانگیریمجتمع فنی ارومیهآموزش های کاربردی و پروژه محور سی شارپآموزش سی شارپ در ارومیه
بنده دارای مدارک بین المللی شبکه ,برنامه نویسی, سرورهای ویندوزی و لینوکس هستم بیش از ده سال سابقه تدریس در زمینه های یاد شده را دارم. آموزش تخصص ماست با ما حرفه ای شوید 09149431772 مجتمع فنی ارومیه
شاید از این پست‌ها خوشتان بیاید