ایجاد 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 تشکر