私はあなたのViewModelにコンストラクタを介して何かを注入したいと仮定しています。例えば、何を表示するかを決定するためにViewが使う種類の設定オブジェクトです。また、MVCがコントローラインスタンスの引数からモデルインスタンスを自動的に作成してバインドしようとすると、このアプローチによって「このオブジェクトに対して定義されたパラメータなしのコンストラクタがありません」というエラーが発生していると想定しています。また、実行時にSiteConfigオブジェクトをコントローラに自動的に挿入するためにDIフレームワークを使用することを前提とします。
これは、私たちが解決しなければならない唯一の問題は、自動的にバインドされたときにコントローラから注入されたオブジェクトをアクションの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;
}
}
}
今、私たちは、実際のコントローラを定義します。私たちはDIのためNinjectを使用していると仮定すると、
public HomeController: BaseController
{
public HomeController(ISiteConfig siteConfig): base(siteConfig) {}
}
にHomeController、Ninjectは自動的にコントローラを作成し、実行時にそのコンストラクタの中に具体的なISiteConfig
オブジェクトを渡すように構成されることになります。
ここで、コントローラにアクションを追加します。
indexアクション
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から派生しているため、(コントローラがBaseControllerから派生しているため)Actionのコントローラで見つけることができるISiteConfigを使用してIndexViewModelインスタンスをスピンアップしようとします。
ISiteConfigが何であるか分かりません。私はそれを実装する必要がありますか? –
ISiteConfigは、ビューに自動的に挿入するSiteConfigオブジェクトのインターフェイスです。 ISiteConfigとSiteConfigは独自の設定オブジェクトを参照します.Viewに提供したいものは何でも、まさにその例です。 –