我假設你想讓你的ViewModel通過它們的構造函數自動注入某些東西 - 例如某種配置對象,視圖將使用它來確定顯示內容。我還假設,當MVC嘗試從Controller Action的參數中自動創建並綁定模型實例時,此方法會導致「無參數定義的此對象的構造函數」錯誤。我們還假設我們將使用DI框架在運行時自動將SiteConfig對象注入到控制器中。
這意味着我們必須解決的唯一問題是如何從Controller中將注入的對象自動綁定到Actions的ViewModel中。
所以讓我們來定義一個基礎模型,讓其他人從中繼承。
BaseViewModel
public class BaseViewModel
{
public ISiteConfig SiteConfig { get; set; }
public BaseViewModel(ISiteConfig siteConfig)
{
this.SiteConfig = siteConfig;
}
}
現在讓我們創建一個從它繼承的典範。
IndexViewModel
public class IndexViewModel : BaseViewModel
{
public string SomeIndexProperty { get; set; }
public IndexViewModel (ISiteConfig siteConfig) : base(siteConfig) {}
}
現在讓我們定義一個基本的控制器,我們的控制器將繼承。
BaseController
public abstract class BaseController : Controller
{
protected BaseController(ISiteConfig siteConfig)
{
_siteConfig = siteConfig;
}
private readonly ISiteConfig _siteConfig;
public ISiteConfig SiteConfig
{
get
{
return _siteConfig;
}
}
}
現在我們定義我們的實際控制人。
的HomeController
public HomeController: BaseController
{
public HomeController(ISiteConfig siteConfig): base(siteConfig) {}
}
假設我們使用Ninject爲DI,Ninject將被配置爲自動創建控制器並在運行時通過一個具體的ISiteConfig
對象到其構造函數。
現在我們將我們的動作添加到控制器。
索引操作
public ActionResult Index(IndexViewModel model)
{
return View(model);
}
所以這是在沒有做別的事情,MVC將與「無參數的構造函數」的錯誤,如果你嘗試調用索引操作引爆點,因爲MVC可以」找到一個不帶參數的ViewModel構造函數。
等等答案。我們需要重寫默認的ModelBinder。
BaseViewModelBinder
public class BaseViewModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
if (modelType == typeof(BaseViewModel) || modelType.IsSubclassOf(typeof(BaseViewModel)))
{
var baseControl = controllerContext.Controller as BaseController;
if (baseControl == null)
{
throw new Exception("The Controller must derive from BaseController");
}
var instance = Activator.CreateInstance(modelType, baseControl.SiteConfig);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => instance, modelType);
return instance;
}
else
{
return base.CreateModel(controllerContext, bindingContext, modelType);
}
}
}
我們需要global.asax.cs
到其設置爲默認的模型綁定:
protected void Application_Start()
{
...
ModelBinders.Binders.DefaultBinder = new BaseViewModelBinder();
}
這就是全部。如您所見,當您現在查看索引操作時,MVC將使用我們的自定義模型綁定器。它會意識到IndexViewModel派生自BaseViewModel,因此會嘗試使用它可以在Action的Controller中找到的ISiteConfig來旋轉一個IndexViewModel實例(因爲Controller派生自BaseController)。
我不明白ISiteConfig是什麼。我必須執行它嗎? – 2017-05-09 17:21:25
ISiteConfig是您希望被自動注入到視圖中的SiteConfig對象的接口。 ISiteConfig和SiteConfig引用了你自己製作的配置對象 - 無論你想提供給你的視圖,只是例如。 – 2017-05-12 10:32:14