ایجاد Web API با استفاده از الگوی Repository و تزریق وابستگی (Dependency Injection)

پنجشنبه 27 آبان 1395

در این مقاله ، مطالبی را در مورد چگونگی ایجاد Web API با استفاده از الگوی لایه بندی Repository و تزریق وابستگی ها ، ارائه خواهیم داد . در این مقاله ما بر روی مباحثی که در زیر ذکر میشود ، تمرکز خواهیم داشت : - معماری لایه بندی در پروژه های Web API - کار با الگوی Repository در پروژه های Web API - کار با Dependency Injection در Web API - توضیح و شرح Entity Framework برای کار با داده ها

ایجاد Web API با استفاده از الگوی Repository  و تزریق وابستگی (Dependency Injection)

معرفی :
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

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید