在codeproject看到一篇文章,群裡的一個朋友要幫忙我翻譯一下順便貼出來,這篇文章適合新手,也算是對MEF的一個簡單用法的介紹。 Introduction In a simple statement if I want to define an ASP.NET MVC controller then I can say that classes that are responsible for receiving and processing incoming http requests, handling client input, and sending response back to the client. Controllers also act as a coordinator between Model (Business) and View (Presentation). ASP.NET MVC framework itself creates controller objects at run time. There is only one prerequisite, that is controller class must have a parameter less constructor. But if you need to pass some objects with constructor then what will happen? Simply framework will fail to create controller object. In that case we need to create controller objects by our self and inject dependency there. There are many ways you can inject dependency to a class. For example, it might be Property setter,Method, Constructor injection. In this article I will explain how to inject controller dependency to ASP.NET MVC framework with the help of constructor. Without creating custom controller factory inject dependency to controllers are not possible. So I will also explain how to create a very simple custom controller factory and register it to ASP.NET MVC framework. I will also demonstrate a way to inject dependency to controllers using Managed Extensible Framework (MEF). 介紹如果我想用一個簡單的宣告去定義一個ASP.NET MVC 控制器。然後我會說這個類是負責接收和處理傳入的http請求,操作客戶端輸入,並將響應傳送回客戶端。Controllers 還可以扮演Model(業務層)和View(表現層)之間的中間人。ASP.NET MVC框架本身在執行時會建立控制器物件。但是有一個前提,那就是控制器類至少必須有一個引數的建構函式。但是,如果你需要傳遞一些物件給建構函式,那麼會發生什麼呢?簡單的框架,將無法建立控制器物件。在這種情況下,我們需要建立控制器實現自我依賴注入。 有很多方法,你可以注入依賴一類。例如,它可能是物業二傳手,方法, 建構函式注入。在這篇文章中,我將解釋如何注入控制器的依賴ASP.NET MVC框架的建構函式的幫助。沒有建立自定義控制器工廠注入依賴控制器是不可能的。所以,我也將解釋如何建立一個非常簡單的自定義控制器工廠,並把它註冊到ASP.NET MVC框架。我還將展示一種方式來注入依賴使用託管擴充套件框架(MEF)的控制器。
這裡有很多方法可以向類中進行依賴注入。例如,它可能是屬性setter方法、建構函式注射。在本文中我將解釋向ASP.NETMVC的控制器的使用建構函式輔助進行依賴注入。淨MVC框架建構函式的幫助。沒有建立自定義控制器工廠注入依賴控制器是不可能的。所以我也會演示如何建立一個非常簡單的自定義控制器廠,並把它註冊到ASP.NET MVC框架, 我還將演示一種使用託管擴充套件的框架(MEF)的依賴注入控制器方式。 Why Need to Inject Controller Dependency?In real life application development, you will see almost all ASP.NET MVC applications are needed to inject its dependent component. You can create component directly inside the controller instead of inject them. In that case the controller will be strongly coupled on those components. If any component's implementation is changed or new version of that component is released then you must change controller class itself. Another problem you will face when you will do unit test. You cannot do unit test of those controllers independently (within isolation). You cannot take mocking features from unit testing framework. Without mocking, you cannot do unit test of your code in isolated environment. 在現實生活中的應用程式開發,你會看到,幾乎所有的ASP.NET MVC應用程式都需要注入其依賴的元件。您可以在控制器內部創直接建元件物件代替注入。在這種情況下,控制器將被強耦合到這些元件。如果任何元件的實現變更或新版本元件被髮布,那麼,你必須修改控制器類。當你要做單元測試時,您將面臨的另一個問題。 你不能單獨對這些控制器類做單元測試。你不能通過單元測試框架實現功能的模擬。沒有模擬,你就不能在隔離的環境中做單元測試的程式碼。 Controller Static StructureASP.NET MVC framework’s controller structure is defined inside an abstract class named Controller. If you want to create any controller, first you will create a class which must be inherited from abstract class 控制器靜態結構ASP.NET MVC框架的控制器結構被定義在名為Controller的抽象類。如果你想建立任何控制器,首先您必須必須繼承自抽象的Controller類 。Controller類的層次結構的UML類圖如下: All controllers root interface is 所有控制器的根介面 Simple Custom Controller Definition
If you create an ASP.NET MVC project, you will get two default controllers. One is 簡單的自定義控制器定義如果你建立一個ASP.NET MVC專案時,你會得到兩個預設控制器。一個是 If you look at the 如果你檢視HomeController中類定義,那麼你會發現,這個類沒有建構函式。
public class HomeController : Controller { public ActionResult Index() { ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; return View(); } public ActionResult About() { ViewBag.Message = "Your app description page."; return View(); } } We all know that if there is no constructor defined then at compile time .NET Framework creates a default parameter-less constructor. 我們都知道,如果沒有建構函式的定義,那麼在編譯的時候,NET Framework會建立一個預設的無引數的建構函式。 public class HomeController : Controller { public HomeController() { } } Now I will create ILogger interface and its implementation DefaultLogger class. Home controller class will use that ILogger object. I will inject it throw constructor. 現在我將建立一個ILogger介面及其實現類defaultlogger。HomeController類將使用ILogger物件。我會把它注入建構函式。 public interface ILogger { void Log(string logData); } public class DefaultLogger : ILogger { public void Log(string logData) { System.Diagnostics.Debug.WriteLine(logData, "default"); } } HomeController with ILogger constructor injection looks: HomeController的用的ILogger注入建構函式如下: public class HomeController : Controller { private readonly ILogger _logger; public HomeController(ILogger logger) { _logger = logger; } }
Still I do not find any place where I can create 我仍然沒有找到任何地方,在那裡我可以在我的程式碼庫建立DefaultLogger物件,我不是自己建立 HomeController的物件,所以我找不到建立 DefaultLogger物件的地方以及如何傳遞
HomeController 引數給HomeController(ILogger logger)建構函式。如果我生成這個專案,那麼,它肯定不會出錯。但在執行時將引發異常。 異常詳細資訊的錯誤頁面將會顯示如下:See the stack trace above, object of class
DefaultContollerActivator throw exception named MissingMethodException . If you go MSDN, search the exception which is raised, you will find it there and there clearly mentions “The exception that is thrown when there is an attempt to dynamically access a method that does not exist.” That is the inner exception message. If see next exception named InvalidOperationException , it is actually wrapped MissingMethodException and there you will find more user friendly message and that is “Make sure that the controller has a parameterless public constructor.” If I want to make HomeController workable then I must add a parameter less constructor and framework will create controller object with the help of that constructor. Question will rise how I can pass DefaultLogger object to that controller? Please keep your patience. 檢視堆疊跟蹤以上,DefaultContollerActivator類的物件 丟擲名為MissingMethodException異常 。如果你去MSDN,搜尋是誰引發的異常,你會發現它有明確的指出“有一個試圖動態訪問的方法時不存在引發的異常。”這是內部異常訊息。如果看到一個異常名為 InvalidOperationException異常,它實際上是包含MissingMethodException,並且你可以找到更多的友好的提示訊息,那就是“確保該控制器具有一個無引數的公共建構函式。”如果我要讓 HomeController的可行的話,我必須新增一個無引數的建構函式在框架的幫助下建立控制器物件。問題是,我怎麼向控制器傳入 DefaultLogger物件?請保持您的耐心。
How MVC Framework Create Controllers?Before start to describe dependency injection process of MVC框架如何建立控制器?開始前描述HomeController的 If you look at the bellow image, you can see that
如果你看看波紋影象,你可以看到, Why Need Custom Controller Factory?Already you know that Default controller factory creates controller object using parameter less constructor. We can inject our controller by parameterless constructor too. See the code below: 為什麼需要自定義控制器工廠?你已經知道,預設控制器工廠建立控制器物件使用無參建構函式。我們可的含參的控制器建構函式實現注入。見下面的程式碼: public class HomeController : Controller { private readonly ILogger _logger; public HomeController():this(new DefaultLogger()) { } public HomeController(ILogger logger) { _logger = logger; } } I found many developers who are misguided the way of the above dependency injection process. This is not dependency injection at all. This actually clearly violate the dependency inversion principle. The principle say that "High level module should not depend upon the low level module, both should depend on abstraction. Details should depends upon abstraction". In above code HomeController itself create DefaultLogger object. So it directly depends on ILogger implementation (DefaultLogger). If in future another implementation comes of ILogger interface then HomeController code itself need to change. So it is probed that it is not proper way to do. So if we need proper way to inject dependency. We need parameterised constructor, by which we can inject our ILogger component. So current implementation of DefaultControllerFactory does not support this requirement. So we need a new custom controller factory. 我發現許多開發者的錯誤就是上述依賴注入過程的方式。這根本不是依賴注入。實際上,這顯然違反了依賴倒置原則。原則上說,“ 高階別不應依賴於低階別的模組模組,都應該依賴於抽象。細節上都要取決於抽象“。在上面的程式碼中的HomeController本身建立DefaultLogger物件。因此,它直接取決於ILogger實現(DefaultLogger)。如果在未來有 ILogger介面 的另一種實現,那麼HomeController的程式碼本身需要改變。所以這種嘗試是不正確的方式。因此,如果我們需要適當的方式進行注入依賴。我們需要含參建構函式,我們可以注入ILogger元件。因此,當前執行的 DefaultControllerFactory 不支援這一要求。因此,我們需要一個新的自定義控制器工廠。建立自定義控制器廠通過實現 public class CustomControllerFactory : IControllerFactory { public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) { ILogger logger = new DefaultLogger(); var controller = new HomeController(logger); return controller; } public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior( System.Web.Routing.RequestContext requestContext, string controllerName) { return SessionStateBehavior.Default; } public void ReleaseController(IController controller) { IDisposable disposable = controller as IDisposable; if (disposable != null) disposable.Dispose(); } }
Now at first you need to register 現在首先你需要在Application_Start方法中向MVC框架註冊CustomControllerFactory。 public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { RegisterCustomControllerFactory (); } } private void RegisterCustomControllerFactory () { IControllerFactory factory = new CustomControllerFactory(); ControllerBuilder.Current.SetControllerFactory(factory); }
If you run the application and see that your parameter-less constructor 如果你執行應用程式會看到無參的HomeController建構函式並沒有被呼叫,含參的 MVC框架呼叫。哇!你的問題很容易就解決了。You can create your controller creation with little generic way using reflection.
您可以使用反射建立控制器泛型方法
public class CustomControllerFactory : IControllerFactory { private readonly string _controllerNamespace; public CustomControllerFactory(string controllerNamespace) { _controllerNamespace = controllerNamespace; } public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) { ILogger logger = new DefaultLogger(); Type controllerType = Type.GetType(string.Concat(_controllerNamespace, ".", controllerName, "Controller")); IController controller = Activator.CreateInstance(controllerType, new[] { logger }) as Controller; return controller; } } first you need to create controller type object from controller full name. Then you create controller object at run time using
首先,您需要從控制器的全名建立控制器型別的物件。然後在執行時使用
Another Approach
Another way you can create your own controller factory. Though MVC framework’s default implementation of 另一種方法
另一種方法,你可以建立自己的控制器工廠。雖然MVC框架的預設實現 public class CustomControllerFactory : DefaultControllerFactory { protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) { ILogger logger = new DefaultLogger(); IController controller = Activator.CreateInstance(controllerType, new[] { logger }) as Controller; return controller; } } Just create my own MEF for Creating Custom Controller FactoryIn real life project you will see experts are using IOC containers inside controller factory for creating/fetching the MEF建立自定義控制器工廠在現實生活中,您將看到專業的專案在控制器工廠內部使用的是Ioc容器建立/讀取Controller物件的。如果您嘗試動態建立依賴物件和控制器物件會引發很多 問題。因此,這將是更好的方法在您的專案使用任意的IOC容器到並註冊所有的依賴物件。您可以使用各種流行的IOC容器,如Castle Windsor, Unity, NInject, StructureMap etc.等,在這種情況下我將演示如何使用託管擴充套件框架(MEF)。MEF並不是一個IOC容器。它是一種層組合。你也可以叫它可插拔的框架,在執行時,你可以插入你的依賴元件。幾乎所有IOC的工作都可以由MEF完成。採用MEF還是IOC這取決於你應用架構的要求。我的建議是,當你需要在執行時修改你的元件時(執行時間外掛在執行),在這種情況下,您可以使用MEF,當您建立元件以及依賴於它的靜態引用的元件,那麼你可以使用IOC。有很多網上公佈文章,哪裡可以找到有關的更多詳細資訊/技術文章。我希望你能多學習,那麼當你使用時很容易地作出決定。順便說一下MEF來自.NET 4.0框架,因此,主要的好處是,不存在第三方元件的依賴。首先,你需要在你的您的專案引用system.ComponentModel.Composition。 Then you create custom Controller Factory. The name of the controller factory is 接下來建立自定義控制器工廠----- public class MefControllerFactory : DefaultControllerFactory { private readonly CompositionContainer _container; public MefControllerFactory(CompositionContainer container) { _container = container; } protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) { Lazy<object, object> export = _container.GetExports(controllerType, null, null).FirstOrDefault(); return null == export ? base.GetControllerInstance(requestContext, controllerType) : (IController)export.Value; } public override void ReleaseController(IController controller) { ((IDisposable)controller).Dispose(); } }
這裡的CompositContainer物件是很像IOC容器。內部GetControllerInstance方法用於獲取取控制器物件。如果發現空值,那麼返回預設的控制器(基類)的物件,否則返回 CompositContainer物件。在建立MefControllerFactory 類,我們需要在在Application Start事件將其註冊到MVC 框架。 protected void Application_Start() { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var composition = new CompositionContainer(catalog); IControllerFactory mefControllerFactory = new MefControllerFactory(composition); ControllerBuilder.Current.SetControllerFactory(mefControllerFactory); } I use MEF的 InheritedExportAttribute ExportAttribute, PartCreationPolicyAttribute 到介面 ILogger , HomeController
Based on these attributes MEF framework create objects. Just one important think you should remember that when you will use MEF, you should decorate your controllers through 基於這些屬性MEF框架建立物件。只是一個重要的知識點你應該記住,當你將使用MEF,你應該裝飾你的控制器通過PartCreationPolicyAttribute 併為控制器建立的每個請求策略的物件設定生命週期 [PartCreationPolicy(CreationPolicy.NonShared)], 如果沒有就會報錯。預設情況下,它將使用SharedCreation策略。
Points of InterestI tried to explain various ways to create controller factory and inject its dependency in a very simple and straight forward way. First and second approach is just make understandable to the process of building and injecting controller and its dependency. You should not use that approach directly to the real life application. You can take IOC or MEF framework for that. You can do more research on MEF and learn MEF usage and best practices after that you will use it to your real life projects. Near future I have a plan to write another article that will demonstrate to use of various IOC containers like Windsor, Unity, NInject, StrucutureMap etc. to inject controller dependency injection and a comparative study with them. In my sample downloadable code I used visual studio 2012 with .NET framework 4.5. Anyone can download and play with that. 亮點我試圖解釋各種不同的方法來建立一個非常簡單直觀的注入依賴的控制器的工廠方法。這兩種方法是要理解構造和控制器的依賴注入過程。你不應該將其直接應用與真實的專案中。你可以使用IOC或MEF框架。你可以做更多的研究和學習使用MEF及最佳做法之後,可以將它應用到你的現實生活中的專案。不久,我計劃寫一篇文章,將展示使用多種IoC容器像Windsor, Unity, NInject, StrucutureMap etc.等注入控制器依賴注入並進行比較和研究。 在我的示例下載的程式碼,我用的是Visual Studio 2012 .NET Framework 4.5。任何人都可以下載玩一玩。 |
MVC Controller Dependency Injection for Beginners【翻譯】
相關文章
- Spring MVC for beginners 筆記SpringMVC筆記
- Why MVC is Better?(翻譯)MVC
- 理解ASP.NET Core - [03] Dependency InjectionASP.NET
- Dependency Injection-依賴注入詳解依賴注入
- WebForms VS. MVC(翻譯)WebORMMVC
- .Net DI(Dependency Injection)依賴注入機制依賴注入
- Laravel Dependency Injection (依賴注入) 概念詳解Laravel依賴注入
- Ioc模式 Dependency Injection模式和AOP討論模式
- SAP Spartacus 中的依賴注入 Dependency Injection 介紹依賴注入
- .NET程式設計5月小結 - Blazor, Unity, Dependency Injection程式設計BlazorUnity
- .net core 原始碼分析(9) 依賴注入(DI)-Dependency Injection原始碼依賴注入
- Asp.net MVC – ControllerASP.NETMVCController
- ABAP模擬Java Spring依賴注入(Dependency injection)的一個嘗試JavaSpring依賴注入
- Spring MVC Controller單例陷阱SpringMVCController單例
- spring MVC -- controller引數的解析SpringMVCController
- 翻譯
- Yurii談翻譯(五)怎樣翻譯更地道:so…that…的翻譯
- Go語言:一文看懂什麼是DI依賴注入(dependency injection)設計模式Go依賴注入設計模式
- Postgres Basic Commands for Beginners
- 如何完成中文翻譯日文線上翻譯
- Yurii談翻譯(四)怎樣翻譯更地道:翻譯如鋪路
- Yurii談翻譯(九)怎樣翻譯更地道:冠詞a的翻譯
- Yurii談翻譯(十)怎樣翻譯更地道:最高階的翻譯
- 翻譯的未來:翻譯機器和譯後編譯編譯
- asp.net mvc get controller name and action nameASP.NETMVCController
- MVC中獲取當前URL、controller、actionMVCController
- Spring MVC 的Controller 結構問題SpringMVCController
- Ubuntu安裝劃詞翻譯軟體Goldendict 單詞翻譯 句子翻譯UbuntuGo
- Yurii談翻譯(六)怎樣翻譯更地道:“as somebody said…”的翻譯AI
- Yurii談翻譯(十三)怎樣翻譯更地道:It is…that…句型諺語的翻譯
- Yurii談翻譯(十四)怎樣翻譯更地道:否定句的翻譯
- 蝴蝶書-task2: 文字推理、摘要、糾錯 transformers實現翻譯 OpenAI翻譯 PyDeepLX翻譯 DeepLpro翻譯ORMOpenAI
- Nginx翻譯Nginx
- [翻譯] TransitionKit
- 翻譯篇
- OllDbg翻譯LLDB
- OpenCV翻譯專案總結二——Mat翻譯OpenCV
- java web mvc-01-Model-View-Controller 概覽JavaWebMVCViewController