ایجاد Web API با استفاده از الگوی Repository و تزریق وابستگی (Dependency Injection)
پنجشنبه 27 آبان 1395در این مقاله ، مطالبی را در مورد چگونگی ایجاد Web API با استفاده از الگوی لایه بندی Repository و تزریق وابستگی ها ، ارائه خواهیم داد . در این مقاله ما بر روی مباحثی که در زیر ذکر میشود ، تمرکز خواهیم داشت : - معماری لایه بندی در پروژه های Web API - کار با الگوی Repository در پروژه های Web API - کار با Dependency Injection در Web API - توضیح و شرح Entity Framework برای کار با داده ها
معرفی :
ASP.Net Web API یک Framework است ، که کار را برای ایجاد سرویس های HTTP ، که دامنه وسیعی از کاربران را شامل میشود ، سهولت میبخشد ، که مرورگرها و دستگاه های موبایل را نیز شامل میشود .
ASP.Net Web API یک پلتفرم ایده آل برای ایجاد برنامه های RESTful در Net Framework. است .
یک Web API چیزی نیست جز کپسوله سازی business logic ، که توسط کاربران مختلف برای ایجاد برنامه های سمت کاربر همانند برنامه های موبایلی یا برنامه های Web ، مورد استفاده قرار می گیرد .
حال ، یک پروژه Web API با لایه هایی که در تصویر زیر مشاهده میکنید ، ایجاد کنید :
تصویر زیر به طور کامل چگونگی ظاهر شدن لایه ها در پروژه بعد از hosting را نشان میدهند :
حال ، ما لایه ها را یک به یک بررسی میکنیم . لایه اولی که بررسی خواهیم کرد لایه Web API است .
این لایه معمولا برای مدیریت درخواست هایی که از سمت کاربر فرستاده میشود مورد استفاده قرار میگیرد . این معمولا شامل کلاس Controllerها میباشد . این کلاس های Controller از API Controlle مشتق میشوند . در هر Controller ، ما چندین Action MEthod داریم که در این متد ها ما منطق برنامه را پیاده سازی میکنیم .
دومین لایه که به بررسی آن خواهیم پرداخت ، لایه IBLL میباشد . در اینجا لایه IBLL ما شامل تمام interface میباشد که تمام کلاس های Abstract یک متد Abstract دارند ، که declare خواهند شد . Controller ها لایه IBLL را فراخوانی خواهد کرد که در این لایه تمام Interface های ما پیاده سازی شده اند .
در اینجا ، ما یک Interface با نام IProduct.cs ایجاد کردیم ، که تمام abstract classها را در اینجا برای بکار بردن در برخی از عملیات ها ، تعریف میکنیم :
همانطور که در زیر نمایش داده شده است ، ما کلاس Abstract class را تعریف کرده ایم :
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Demo.model; namespace Demo.IBll { public interface IProduct { bool SaveProducts(ProductDetailsModel pod); List<ProductDetailsModel> searchdetails(string id); List<ProductDetailsModel> showDetails(); } }
در اینحجا ، ما سه abstract method تعریف کردیم ، همانطور که در بالا ذکر شد .
در زیر لایه Model ما قرار دارد ، که تمام model class ها و مشخصه های آن در این لایه پیاده سازی شده می شود .
در زیر ProductDetailsModel.cs را مشاهده میکنید :
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Demo.model { public class ProductDetailsModel { public long slNo { get; set; } public string ProductName { get; set; } public string ProductDetail { get; set; } public int Price { get; set; } public string ProductType { get; set; } } }
حال ، یک کلاس Helper تعریف میکینم ، که از Interface IProduct ارث بری میکند :
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Demo.IBll; using Demo.model; using AutoMapper; using Demo.Data; namespace Demo.BL { public class ProductManager : IProduct { DemoEntities2 _dbContext = new DemoEntities2(); public bool SaveProducts(ProductDetailsModel pod) { productDetail pd = new productDetail(); pd.ProductName = pod.ProductName; pd.ProductDetail1= pod.ProductDetail; pd.Price = pod.Price; pd.Type = pod.ProductType; _dbContext.productDetails.Add(pd); if(_dbContext.SaveChanges()==1) { return true; } else { return false; } } public List<ProductDetailsModel> searchdetails(string type) { List<ProductDetailsModel> li = new List<ProductDetailsModel>(); var details = _dbContext.productDetails.Where(x => x.Type == type); if(details!=null) { Parallel.ForEach(details, x => { ProductDetailsModel obj = new ProductDetailsModel(); obj.slNo = x.slNo; obj.ProductName = x.ProductName; obj.Price = Convert.ToInt32(x.Price); li.Add(obj); }); return li; } else { return li; } } public List<ProductDetailsModel> showDetails() { List<ProductDetailsModel> li = new List<ProductDetailsModel>(); var details = _dbContext.productDetails; if (details != null) { Parallel.ForEach(details, x => { ProductDetailsModel obj = new ProductDetailsModel(); obj.slNo = x.slNo; obj.ProductName = x.ProductName; obj.Price = Convert.ToInt32(x.Price); li.Add(obj); }); return li; } else { return li; } } public bool DeleteDetails(int id) { var Info = _dbContext.productDetails.Where(m => m.slNo == id).FirstOrDefault(); _dbContext.productDetails.Remove(Info); if (_dbContext.SaveChanges() == 0) return true; return false; } } }
حال ، به سراغ توضیح DataLayer میرویم ، که در ارتباط با پایگاه داده مورد استفاده قرار خواهد گرفت . در این اینجا به پیاده سازی این لایه خواهیم پرداخت :
Model1.edmx را در تصویر زیر مشاهده میفرمایید . این لایه ارتباطی را با پایگاه داده خواهد داشت و مسئولیت هرگونه عملیات مرتبط با پایگاه داده بر عهده این لایه است . در این مقاله ما از Entity Framework
استفاده میکنیم که یک الگوی ORM است .
Microsoft ADO.Net Entity Framewoek یک ORM Framework است که این امکان را به توسعه دهندگان میدهد که با relational data ها کار کنند .
استفاده از EF ، استفاده از LINQ و بازیابی و نگهداری داده ها تحت عنوان اشیائی با نوع Strongly . پیاده سازی Entity Framework سرویس هایی نظیر change tracking, identity resolution, lazy loading و query translation را فراهم میآورد ، بنابراین توسعه دهندگان میتوانند به جای پرداختن به مسئله های پایه اییِ پردازش داده ها ، بروی Business logic مشخص برنامه خودشان تمرکز کنند .
Entity Framework یک ORM Framework است که یک مکانیزم اتوماتیک برای پردازش و ذخیره سازی داده ها در پایگاه داده را ، در اختیار توسعه دهندگان قرار میدهد .
حال ، به چگونگی نوشتن کد در Controller های Web API ، با استفاده از Dependency Injection خواهیم پرداخت . اجازه دهید ابتدا به بررسی این موضوع که dependency Injection چیست ؟ - بپردازیم .
dependency Injection ک تکنیک برای توسعه یک برنامه مستقل میباشد . مستقل بودن برنامه بدین معناست که هر ماژول برنامه باید منحصر به فرد باشد و وابستگی ای به ماژول های دیگر برنامه نداشته باشد . آنها باید Loosly Coupled باشند .
حال به بررسی tightly coupled و loosly coupled در توسعه برنامه نرم افزاری خواهیم پرداخت .
Tight Coupling :
این بدان معناست که دو کلاس یا دو ماژول بطور کامل به یکدیگر وابسته هستند . و این بدان معناست که اعمال تغییر بر روی یکی از آنها قسمت هایی از دیگری را تحت تاثیر خود قرار میدهد و تغییراتی را ایجاد میکند . زمانی که ما یک شی از یک کلاس ایجاد میکنیم و توسط این شی ، متدی از آن کلاس را در کلاس دیگر فراخوانی میکنیم ، در این حالت ما بیان میکنیم که این دو کلاس tightly coupled هستند یا به عبارت دیگر به هم وابسته هستند .
Loose Coupling :
این بدان معناست که دو شی مستقل از یکدیگر هستند ، این بدان معناست که دو شی میتوانند بدون وابسته شدت و ایجاد وابستگی از یکدیگر استفاده کنند . آنها منحصر بفرد هستند . در توسعه نرم افزار ، ما همیشه برنامه های Loosly coupled را ترجیح میدهیم .
حال ، ما به بررسی چگونگی استفاده از Dependency Injection با استفاده از Ninject Container ، میپردازیم .
به Manage NuGet Package بروید ، Ninject را جستجو کنید و آن را نصب کنید .
بعد از نصب این Ninject ، ما سه فایل Assemblies به Refrences ما اضافه خواهد شد :
و یک کلاس NinjectWebCommon.cs به فایل App.Start ما اضافه خواهد شد :
حال ، به کلاس NinjectWebCommon.cs میرویم و همانطور که در زیر مشاهده میکنید ، Dependency را ثبت میکنیم :
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Demo.Data.App_Start.NinjectWebCommon), "Start")] [assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(Demo.Data.App_Start.NinjectWebCommon), "Stop")] namespace Demo.Data.App_Start { using System; using System.Web; using Microsoft.Web.Infrastructure.DynamicModuleHelper; using Ninject; using Ninject.Web.Common; public static class NinjectWebCommon { private static readonly Bootstrapper bootstrapper = new Bootstrapper(); /// <summary> /// Starts the application /// </summary> public static void Start() { DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule)); DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule)); bootstrapper.Initialize(CreateKernel); } /// <summary> /// Stops the application. /// </summary> public static void Stop() { bootstrapper.ShutDown(); } /// <summary> /// Creates the kernel that will manage your application. /// </summary> /// <returns>The created kernel.</returns> private static IKernel CreateKernel() { var kernel = new StandardKernel(); try { kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel); kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>(); RegisterServices(kernel); return kernel; } catch { kernel.Dispose(); throw; } } /// <summary> /// Load your modules or register your services here! /// </summary> /// <param name="kernel">The kernel.</param> private static void RegisterServices(IKernel kernel) { kernel.Bind<Demo.IBll.IProduct>().To<Demo.BL.ProductManager>().InRequestScope(); } } }
در این مورد ، ما باید یک Component را در Ninject Containers ثبت کنیم . حال ما به سراغ شرح الگوی Repository و چگونگی استفاده از آن می پردازیم .
الگوی Repository :
همانطور که ما بر روی معماری لایه ها کار میکنیم ، لایه های پروژه ما نیز باید کاملا مستقل از یکدیگر باشند ، این بدان معناست که لایه Controllerها باید مستقل از لایه های DataAccess باشد . اگر ما در اینجا از tightly coupled استفاده کینم هر تغغییر کوچکی در data-access layer میتواند تغییراتی را در controllerها ایجاد کند .
در زیر چگونگی وضعیت کدهای بدون Repository ما نمایش داده شده اند :
Repository برای ایجاد یک لایه abstract ما بین لایه data access و لایه business logic یک برنامه ، مورد استفاده قرار میگیرد . پیاده سازی این الگوها می تواند به مجزا کردن برنامه شما از هرگونه تغیرات در پایگاه داده ، کمک کند و میتواند unit testing خودکار و توسعه test-driven را سهولت ببخشد .
در اینجا ، یک شی از BLL را در Controller ایجاد میکنیم ، بنابراین هر دوی آنها یعنی هم BLL و هم Controller
tightly coupled هستند . زمانی که برنامه tightly coupled میشوود ، هر گونه تغییری در DAL ، کل Controller ها را تغییرمیدهد .
تغییرات یک چیزی شبیه تغییرات در database ، تغییر تکنیک پردازش داده هستند . بنابراین هرگونه تغغیراتی بر روی front end تغییارتی را اعمال میکند .
اگر برنامه ما tightly coupled می باشد ، عوض کردن آن امری بسیار دشوار است . اگه شما لایه DAL را تغییر دهید ، همانطور که در زیر مشاهده میکنید ، تمام لایه ها در Controller نیاز به تغییر دارند :
این بر روی هر دو لایه تاثیر خواهد گذاشت . در اینجا برای اشاره به مکمانهایی که ممکن است تغییراتی در آن ایجاد شود ما از یک فلش قرمز استفاده کردیه ایم . زمانی که ما از اشیا کلاس DAL استفاده میکنیم ، این امر نیاز است که آن با کلاس SQL DAL جابجا شود .
حال ، پروژه را با استفاده از Repository در نظر میگیریم ، آن چیزی همانند تصویر زیر خواهد شد :
در اینجا ، Controller ما به IBLL اشاره خواهد داشت ، که یک interface است و این Interface در BLL پیاده سازی خواهد شد .
ما یک ADO.Net BAL ساده ایجاد میکینم که از IBLL ارث بری دارد :
با این روش ، ما میتوانیم از پس مشکل تغییر مکرر تکنولوژی پردازش داده ها در پروژه خود ، مقابله کنیم .
به همین دلیل ، ما IBLL و BLL را همانطور که در زیر نمایش داده شده است در پروژه خود داریم :
حال ، پروژه ما تقریبا انجام شده است ، ما برای Dependency Injection نیاز داریم که کدهای زیر را در Controller و کلاس های مربوطه بنویسیم . از ان رو ، کد های کامل عملیات CRUD در ProductDeatils Controller بصورت زیر است :
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; using System.Web.Http; using Demo.model; using Demo.IBll; namespace WEBAPI.Controllers { [RoutePrefix("api/Product")] public class ProductController : ApiController { Demo.IBll.IProduct iproductdetails; public ProductController(Demo.IBll.IProduct _iproductdetails) { iproductdetails = _iproductdetails; } [Route("addProduct")] [HttpPost] public async Task<HttpResponseMessage> saveProductDetails(ProductDetailsModel pod) { Dictionary<string, string> dict = new Dictionary<string, string>(); bool res = false; res = iproductdetails.SaveProducts(pod); if (res == true) { var showmessage = "Product Saved Successfully."; dict.Add("Message", showmessage); return Request.CreateResponse(HttpStatusCode.OK, dict); } else { var showmessage = "Product Not Saved Please try again."; dict.Add("Message", showmessage); return Request.CreateResponse(HttpStatusCode.BadRequest, dict); } } [Route("showList")] [HttpGet] public async Task<HttpResponseMessage> showList() { List<ProductDetailsModel> li = new List<ProductDetailsModel>(); Dictionary<string, string> dict = new Dictionary<string, string>(); var details = iproductdetails.showDetails(); foreach (var x in details) { ProductDetailsModel pcm = new ProductDetailsModel(); pcm.slNo = x.slNo; pcm.ProductName = x.ProductName; pcm.Price = x.Price; li.Add(pcm); } return Request.CreateResponse(HttpStatusCode.OK, li); } [Route("searchProduct")] [HttpPost] public async Task<HttpResponseMessage> searchProduct(ProductDetailsModel pod) { List<ProductDetailsModel> li = new List<ProductDetailsModel>(); Dictionary<string, string> dict = new Dictionary<string, string>(); var details = iproductdetails.searchdetails(pod.ProductType); foreach(var x in details) { ProductDetailsModel pcm = new ProductDetailsModel(); pcm.slNo = x.slNo; pcm.ProductName = x.ProductName; pcm.Price = x.Price; li.Add(pcm); } return Request.CreateResponse(HttpStatusCode.OK,li); } } }
حال ، پروژه را ذخیره کنید ، آن را Build کنید .
با این روش ، ما میتوانیم با استفاده از الگوی Repository و تزریق وابستگی ، Web API ای را ایجاد کنیم .
آموزش asp.net mvc
- ASP.net MVC
- 3k بازدید
- 10 تشکر