將依賴項注入自定義模型綁定器並使用 InRequestScope 使用 Ninject
我將 NInject 與 NInject.Web.Mvc 一起使用。
首先,我創建了一個簡單的測試項目,我希望
IPostRepository在同一個 Web 請求期間在控制器和自定義模型綁定器之間共享一個實例。在我的真實項目中,我需要這個,因為我遇到了IEntityChangeTracker問題,我實際上有兩個儲存庫訪問同一個對像圖。所以為了讓我的測試項目簡單,我只是想共享一個虛擬儲存庫。我遇到的問題是它適用於第一個請求,僅此而已。相關程式碼如下。
NInject 模組:
public class PostRepositoryModule : NinjectModule { public override void Load() { this.Bind<IPostRepository>().To<PostRepository>().InRequestScope(); } }自定義模型綁定器:
public class CustomModelBinder : DefaultModelBinder { [Inject] public IPostRepository repository { get; set; } public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { repository.Add("Model binder..."); return base.BindModel(controllerContext, bindingContext); } } public class HomeController : Controller { private IPostRepository repository; public HomeController(IPostRepository repository) { this.repository = repository; } public ActionResult Index(string whatever) { repository.Add("Action..."); return View(repository.GetList()); } }全球突擊:
protected override void OnApplicationStarted() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); ModelBinders.Binders.Add(typeof(string), kernel.Get<CustomModelBinder>()); }這樣做實際上是創建 2 個單獨的實例
IPostRepository而不是共享實例。關於將依賴項注入我的模型綁定器,我在這裡缺少一些東西。我上面的程式碼基於NInject.Web.Mvc wiki中描述的第一種設置方法,但我都嘗試過。當我確實使用第二種方法時,
IPostRepository只會為第一個 Web 請求共享,之後預設不共享實例。但是,當我確實開始工作時,我使用的是預設值DependencyResolver,因為我一生都無法弄清楚如何對 NInject 做同樣的事情(因為核心隱藏在 NInjectMVC3 類中)。我是這樣做的:ModelBinders.Binders.Add(typeof(string), DependencyResolver.Current.GetService<CustomModelBinder>());我懷疑這只是第一次起作用的原因是因為這不是通過 NInject 解決它,所以生命週期實際上是由 MVC 直接處理的(儘管這意味著我不知道它是如何解決依賴關係的)。
那麼我該如何正確註冊我的模型綁定器並讓 NInject 注入依賴項呢?
MVC 為多個請求重用 ModelBinders。這意味著它們的生命週期比請求範圍更長,因此不允許依賴具有較短請求範圍生命週期的對象。
改為使用工廠為 BindModel 的每次執行創建 IPostRepository
啟動並執行 Ninject 工廠擴展實際上非常簡單,但是從現有答案中我並不清楚。
工廠擴展外掛是先決條件,可以通過 NUGet 安裝:
Install-Package Ninject.Extensions.Factory您只需要將工廠注入模型綁定器的某個地方,例如:
private IPostRepositoryFactory _factory; public CustomModelBinder(IPostRepositoryFactory factory) { _factory = factory; }然後為工廠創建一個介面。工廠的名稱和方法的名稱實際上根本不重要,只是返回類型。(很高興知道您是否想注入 NHibernate 會話,但又不想擔心為 引用正確的命名空間
ISessionFactory,這也有助於了解GetCurrentRepository它在上下文中的實際作用):public interface IPostRepositoryFactory { IPostRepository CreatePostRepository(); }然後,假設您
IPostRepository已經被 Ninject 正確管理,擴展程序將通過呼叫 .ToFactory() 方法為您完成所有其他工作。kernel.Bind<IPostRepository().To<PostRepository>(); kernel.Bind<IPostRepositoryFactory>().ToFactory();然後你只需在你需要的程式碼中呼叫你的工廠方法:
var repo = _factory.CreatePostRepository(); repo.DoStuff();
GetXXX(更新:如果會話中不存在該服務,顯然命名您的工廠函式實際上會失敗。因此,您實際上必須對命名該方法的名稱有些小心。)