Asp.net-Mvc

將依賴項注入自定義模型綁定器並使用 InRequestScope 使用 Ninject

  • October 9, 2012

我將 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(更新:如果會話中不存在該服務,顯然命名您的工廠函式實際上會失敗。因此,您實際上必須對命名該方法的名稱有些小心。)

引用自:https://stackoverflow.com/questions/9186560