4

現在我ViewModel看起來是這樣的:MVC 6自定義模型綁定使用依賴注入

public class MyViewModel 
{ 
    private readonly IMyService myService; 

    public ClaimantSearchViewModel(IMyService myService) 
    { 
     this.myService = myService; 
    } 
} 

Controller消耗這個ViewModel看起來是這樣的:

public class MyController : Controller 
{ 
    private readonly IMyService myService; 
    public HomeController(IMyService myService) 
    { 
     this.myService = myService; 
    } 

    public IActionResult Index() 
    { 
     var model = new MyViewModel(myService); 

     return View(model); 
    } 

    [HttpPost] 
    public async Task<IActionResult> Find() 
    { 
     var model = new MyViewModel(myService); 
     await TryUpdateModelAsync(model); 

     return View("Index", model); 
    } 
} 

我需要的是我的Controller到看起來是這樣的:

public class MyController : Controller 
{ 
    private readonly IServiceProvider servicePovider; 
    public MyController(IServiceProvider servicePovider) 
    { 
     this.servicePovider = servicePovider; 
    } 

    public IActionResult Index() 
    { 
     var model = servicePovider.GetService(typeof(MyViewModel)); 

     return View(model); 
    } 

    [HttpPost] 
    public IActionResult Index(MyViewModel model) 
    { 
     return View(model); 
    } 
} 

Righ牛逼現在,調用第一Index方法(在我Startup class

builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource(x => x.Name.Contains("ViewModel"))); 

)工作正常,但做POSTIndex(MyViewModel model)給你一個No parameterless constructor defined for this object例外。我意識到custom model binder可以使用我的DI將是最可能的解決方案...但我無法找到任何幫助,甚至可以從這裏開始。請幫助我,尤其是在MVC 6Autofac

+1

檢查這個【答案】(http://stackoverflow.com/a/23571035/3432471) –

+0

是的,我已經看到了,我們終於得到了這個工作,但不得不用一些黑客的手段來完成它......爲了解決這個問題,我們現在需要這個問題的答案(由我的同事問) http://stackoverflow.com/q/35640858/550975然後我們將在這裏分享我們的實施 –

+0

我也在這裏發佈了這個問題:https://groups.google.com/forum/#!topic/autofac/1Zin8oh7x1E –

回答

2

我們來到這裏的答案:https://github.com/aspnet/Mvc/issues/4167

答案是使用:[FromServices]

我的模型最終看起來像這樣:

public class MyViewModel 
{ 
    [FromServices] 
    public IMyService myService { get; set; } 

    public ClaimantSearchViewModel(IMyService myService) 
    { 
     this.myService = myService; 
    } 
} 

雖然這是可悲的,以使該財產public,它比不得不使用custom model binder更難過。

此外,假設你應該能夠通過[FromServices]作爲Action方法的參數的一部分,它確實解決了類,但是打破了模型綁定...即我的屬性沒有被映射。它看起來像這樣:(但同樣,這不起作用所以用上面的例子)

public class MyController : Controller 
{ 
    ... same as in OP 

    [HttpPost] 
    public IActionResult Index([FromServices]MyViewModel model) 
    { 
     return View(model); 
    } 
} 

更新1

[FromServices]工作後屬性,我們可以決定該財產注入在所有我們的ViewModels不是我們想要去的方式,特別是在考慮使用測試進行長期維護時。所以我們決定刪除[FromServices]屬性,得到了我們的自定義模型綁定工作:

public class IoCModelBinder : IModelBinder 
{ 
    public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext) 
    { 
     var serviceProvider = bindingContext.OperationBindingContext.HttpContext.RequestServices; 

     var model = serviceProvider.GetService(bindingContext.ModelType); 
     bindingContext.Model = model; 

     var binder = new GenericModelBinder(); 
     return binder.BindModelAsync(bindingContext); 
    } 
} 

它註冊這樣的StartupConfigureServices方法:

 services.AddMvc().AddMvcOptions(options => 
     { 
      options.ModelBinders.Clear(); 
      options.ModelBinders.Add(new IoCModelBinder()); 

     }); 

就是這樣。 (甚至不知道options.ModelBinders.Clear();是必要的。)

更新2 通過得到這個工作(在幫助https://github.com/aspnet/Mvc/issues/4196)的各種迭代去後,這裏是最後的結果:

public class IoCModelBinder : IModelBinder 
{ 
    public async Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext) 
    { // For reference: https://github.com/aspnet/Mvc/issues/4196 
     if (bindingContext == null) 
      throw new ArgumentNullException(nameof(bindingContext)); 

     if (bindingContext.Model == null && // This binder only constructs viewmodels, avoid infinite recursion. 
       (
        (bindingContext.ModelType.Namespace.StartsWith("OUR.SOLUTION.Web.ViewModels") && bindingContext.ModelType.IsClass) 
         || 
        (bindingContext.ModelType.IsInterface) 
       ) 
      ) 
     { 
      var serviceProvider = bindingContext.OperationBindingContext.HttpContext.RequestServices; 
      var model = serviceProvider.GetRequiredService(bindingContext.ModelType); 

      // Call model binding recursively to set properties 
      bindingContext.Model = model; 
      var result = await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(bindingContext); 

      bindingContext.ValidationState[model] = new ValidationStateEntry() { SuppressValidation = true }; 

      return result; 
     } 

     return await ModelBindingResult.NoResultAsync; 
    } 
} 

你會明顯地要替換OUR.SOLUTION...無論namespace是您ViewModels我們的註冊:

 services.AddMvc().AddMvcOptions(options => 
     { 
      options.ModelBinders.Insert(0, new IoCModelBinder()); 
     }); 
+0

在最新的ASP.NET Core 1.0中,'bindingContext'上沒有'OperationBindingContext',你有沒有更新最新的asp.net核心? – psulek

+1

是:https://github.com/Serjster/IOCModelBinderExample/tree/ASPNETRTMVersion –