سفارشی کردن Controller factory توکار و فرصتی برای تزریق وابستگیها به کنترلر
پنج شنبه 28 آبان 1394 8:05 AM
در مقالهی قبلی ( + ) به این لحاظ که بهترین راه نشان دادن نحوهی کارکرد Controller Factory ایجاد یک نمونهی سفارشی بود، آن رابررسی کردیم و برای اکثریت برنامهها و سناریوها، کلاس توکار Controller Factory به نام DefaultControllerFactory کفایت میکند.
پس از وصول یک درخواست از طریق سیستم مسیریابی، factory پیش فرض (DefaultControllerFactory) به بررسی rout data پرداخته تا خاصیت Controller آن را بیابد و سعی در پیدا کردن کلاسی در برنامه خواهد داشت که مشخصات ذیل را دارا باشد:
کلاس DefaultControllerFactory در صورت یافتن کلاسی مطابق قواعد فوق و مناسب درخواست رسیده، وهلهای از آن را به کمک Controller Activator ایجاد میکند. میبینید که با برپایی چند قاعدهی ساده، factory پیش فرض، نیاز به ثبت کنترلرها را به منظور معرفی و داشتن لیستی برای بررسی از طرف برنامه نویس (مثلا درج نام کلاسهای کنترلر در یک فایل پیکربندی)، مرتفع ساخته است.
اگر بخواهید به فضاهای نام خاصی برای یافتن آنها توسط factory پیش فرض، برتری قائل شوید، باید در متد Application_Start فایل global.asax.cs مانند ذیل عمل نمایید:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Routing; using ControllerExtensibility.Infrastructure; namespace ControllerExtensibility { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); ControllerBuilder.Current.DefaultNamespaces.Add( "MyControllerNamespace" ); ControllerBuilder.Current.DefaultNamespaces.Add( "MyProject.*" ); } } } |
سفارشی کردن وهله سازی کنترلرها توسط DefaultControllerFactory
مهمترین دلیلی که نیاز داریم factory پیش فرض را سفارشی کنیم، استفاده از تزریق وابستگیها (DI) به کنترلرهاست. راههای متعددی برای این کار وجود دارند که انتخاب بهترین روش بسته به چگونگی بکارگیری DI در برنامه شماست:
الف) تزریق وابستگی به کنترلر با ایجاد یک controller activator سفارشی
کدهای اینترفیس IControllerActivator مطابق ذیل است:
1
2
3
4
5
6
7
8
|
namespace System.Web.Mvc { using System.Web.Routing; public interface IControllerActivator { IController Create(RequestContext requestContext, Type controllerType); } } |
این اینترفیس حاوی متدی به نام Create است که شیء RequestContext به آن پاس داده میشود و یک Type که مشخص میکند کدام کنترلر باید وهله سازی شود. در کدهای ذیل در قسمت (return (IController)ObjectFactory.GetInstance(controllerType فرض بر این است که در پروژه برای تزریق وابستگی، StructureMapFactory را به کار گرفتهایم و سیم کشیهای لازم قبلا صورت گرفته است. چنانچه با StructureMap آشنایی ندارید به این مقاله سایت (استفاده از StructureMap به عنوان یک IoC Container) مراجعه نمایید.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
using ControllerExtensibility.Controllers; using System; using System.Web.Mvc; using System.Web.Routing; namespace ControllerExtensibility.Infrastructure { public class StructureMapControllerActivator : IControllerActivator { public IController Create(RequestContext requestContext, Type controllerType) { return (IController)ObjectFactory.GetInstance(controllerType); } } } |
در شکل فوق منظور از CustomControllerActivator یک پیاده سازی از اینترفیس IControllerActivator مانند کلاس StructureMapControllerActivator است.
برای استفاده از این activator سفارشی نیاز داریم وهلهای از آن را به عنوان پارامتر به سازندهی کلاس DefaultControllerFactory ارسال کنیم و نتیجه را در متد Application_Start فایل global.asax.cs ثبت کنیم.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Routing; using ControllerExtensibility.Infrastructure; namespace ControllerExtensibility { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); ControllerBuilder.Current.SetControllerFactory( new DefaultControllerFactory( new StructureMapControllerActivator())); } } } |
ب) تحریف و بازنویسی متدهای کلاس DefaultControllerFactory
میتوان متدهای کلاس مشتق شدهی از DefaultControllerFactory را override کرد و برای اهدافی نظیر DI از آن بهره جست. جدول ذیل سه متدی که میتوان با تحریف آنها به مقصود رسید، توصیف شدهاند:
متد | نوع بازگشتی | توضیحات |
CreateController | IController | پیاده سازی کنندهی متد Createontroller از اینترفیس IControllerFactory است و به صورت پیش فرض متد GetControllerType را جهت تعیین نوعی که باید وهله سازی شود، صدا میزند و سپس کنترلر وهله سازی شده را به متد GetControllerInstance ارسال میکند. |
GetControllerType | Type | وظیفهی نگاشت درخواست رسیده را به Controller type عهده دار است. |
GetControllerInstance | IController | وظیفه ایجاد وهلهای از نوع مشخص شده را عهده دار است. |
شیوهی تحریف متد GetControllerInstance
1
2
3
4
5
6
7
|
public class StructureMapControllerFactory : DefaultControllerFactory { protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { return ObjectFactory.GetInstance(controllerType) as Controller; } } |
شیوهی ثبت در فایل global.asax.cs و در متد Application_start :
1
|
ControllerBuilder.Current.SetControllerFactory( new StructureMapControllerFactory()); |