هدف از این قسمت، ارائه راه حلی برای حالت تزریق وابستگیها در سازندههای کنترلرهای ASP.NET MVC به صورت خودکار است.
به صورت پیش فرض، ASP.NET MVC به کنترلرهایی نیاز دارد که سازنده آنها فاقد پارامتر باشند. از این جهت که بتواند به صورت خودکار آنها را وهله سازی کرده و مورد استفاده قرار دهد. بنابراین به نظر میرسد که در اینجا نیز به همان روش معروف استفاده از الگوی Service locator و تکرار مدام کدهایی مانند ObjectFactory.GetInstance در سراسر برنامه خواهیم رسید که آنچنان مطلوب نیست.
اما ... در ASP.NET MVC میتوان وهله ساز پیش فرض کنترلرها را با پیاده سازی کلاس DefaultControllerFactory به طور کامل تعویض کرد. یعنی اگر در اینجا بجای وهله ساز پیش فرض، از وهله سازی انجام شده توسط IoC Container خود بتوانیم استفاده کنیم، آنگاه کار تزریق وابستگیها در سازندههای کنترلرها نیز خودکار خواهد گردید.
public class StructureMapControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
throw new InvalidOperationException(string.Format("Page not found: {0}", requestContext.HttpContext.Request.Url.AbsoluteUri.ToString(CultureInfo.InvariantCulture)));
return ObjectFactory.GetInstance(controllerType) as Controller;
}
}
در کدهای فوق نمونهای از این پیاده سازی را با استفاده از امکانات StructureMap ملاحظه میکنید. به این ترتیب در زمان وهله سازی خودکار یک کنترلر، اینبار StructureMap وارد عمل شده و وابستگیهای برنامه را مطابق تعاریف ObjectFactory.Initialize ذکر شده، به سازنده کلاس کنترلر تزریق میکند.
برای استفاده از این ControllerFactory جدید تنها کافی است بنویسیم:
protected void Application_Start()
{
//Set current Controller factory as StructureMapControllerFactory
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
}
و ... همین!
اکنون نوشتن یک چنین کنترلرهایی که سازنده آنها دارای پارامتر است، مجاز خواهد بود و تزریق وابستگیها در سازندهها به صورت خودکار توسط IoC Container مورد استفاده انجام میشود.
public partial class LoginController : Controller
{
readonly IUsersService _usersService;
public LoginController(IUsersService usersService)
{
_usersService = usersService;
}
بدیهی است سایر مسایل مانند تنظیمات اولیه IoC Container، تهیه لایه سرویس و غیره مانند قبل است و تفاوتی نمیکند.
روش دوم تزریق خودکار وابستگیها در برنامههای ASP.NET MVC
روش پیاده سازی و تعویض DefaultControllerFactory پیش فرض، متداولترین روش خودکار سازی تزریق وابستگیها در ASP.NET MVC است. روش دیگری نیز بر اساس پیاده سازی اینترفیس توکار IDependencyResolver معرفی شده در ASP.NET MVC 3.0 به بعد، وجود دارد. این روش علاوه بر ASP.NET MVC در کنترلرهای مخصوص Web API نیز کاربرد دارد. حتی SignalR نیز دارای کلاس پایهای به نام DefaultDependencyResolver با امضای مشابه IDependencyResolver است.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using StructureMap;
namespace Prog
{
public class StructureMapDependencyResolver : IDependencyResolver
{
public object GetService(Type serviceType)
{
if (serviceType.IsAbstract || serviceType.IsInterface || !serviceType.IsClass)
return ObjectFactory.TryGetInstance(serviceType);
return ObjectFactory.GetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return ObjectFactory.GetAllInstances(serviceType).Cast<object>();
}
}
}
یک نمونه از پیاده سازی آنرا به کمک StructureMap در اینجا ملاحظه میکنید. برای ثبت آن در برنامه خواهیم داشت:
protected void Application_Start()
{
DependencyResolver.SetResolver(new StructureMapDependencyResolver());
}
در Web API باید GlobalConfiguration.Configuration.DependencyResolver تنظیم شود. البته IDependencyResolver آن در فضای نام دیگری به نام System.Web.Http.Dependencies قرار گرفته است؛ اما کلیات آن تفاوتی نمیکند. نمونهی نهایی و تکمیل شدهی آنرا در اینجا میتوانید مطالعه کنید:
«
تزریق خودکار وابستگیها در ASP.NET Web API به همراه رها سازی خودکار منابع IDisposable »
دریافت مثال کامل بحث جاری:
DI06.zip