视图模型实例的构造方法注入作为一种行动方法参数 [英] Constructor injection of a View Model instance used as an Action method parameter

查看:231
本文介绍了视图模型实例的构造方法注入作为一种行动方法参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在创建视图模型,你可以填充选项(例如,在下拉列表中)到视图模型的setter属性。
问题是,当视图模型后来被作为参数传递(由框架!)到操作方法,这些属性值也不能自动成为
重新填充,所以如果你需要重新显示,因为验证错误的形式,你需要再次重新填充这些选项。

When a view model is created you can populate the options (e.g. used in a dropdown list) into a setter property of the view model. The problem is that when that view model is later passed as a parameter (by the framework!) into an action method, those property values has not become automagically repopulated, so if you need to redisplay the form because of validation errors, you need to repopulate those options again.

一个潜在的解决方案,我在这个问题询问具体而言,就是如何让MVC框架实例化构造函数注入视图模型,这将提供视图模型构造具有某种数据访问对象的实现(例如,可用于检索选项需要的时候,通过视图(如辅助方法DropDownListFor)?一个仓库)

One potential solution, which I am asking for specifically in this question, is how to make the MVC framework instantiate the view model with constructor injection, which would provide the view model constructor with an implementation of some kind of data access object (e.g. a repository) that can be used for retrieving the options when they are requested by the view (e.g. in the helper method "DropDownListFor") ?

我觉得解决方案可能是与IModelBinderProvider或IModelBinder的实现,但这些东西从例如code在这里和那里的净片段经试验后,我仍然在寻找一个完全工作的例子,与下载的可执行code,没有任何丢失一块如何把所有的东西放在一起的。

I think the solution might have something to do with implementations of IModelBinderProvider or IModelBinder but after having experimented with these things from example code snippets here and there on the net, I am still looking for a completely working example, with downloadable executable code without any missing piece of how putting all things together.

如果你正在寻找如何填充选择列表,例如一些替代的讨论以Dependecy查找而不是Dependecy注入你可能想看看下面的讨论:
最好的方式来填充的SelectList的视图模型上GET / POST
<一href=\"http://stackoverflow.com/questions/7603519/best-way-to-populate-selectlist-for-viewmodel-on-get-post\">Best方式来填充的SelectList的视图模型上GET / POST

If you are looking for some alternative discussion about how to populate a select list, e.g. with "Dependecy Lookup" instead of "Dependecy Injection" you may want to check out the following discussion: Best way to populate SelectList for ViewModel on GET/POST Best way to populate SelectList for ViewModel on GET/POST

几天前我写了下面的那个线程对Dependecy注入后续-的问题,我现在正在寻找在这个线程:
http://stackoverflow.com/a/8674525/310457
(其中提供了有关我要寻找的解决问题的code为例)

Some days ago I wrote the following follow-up-question in that thread about the "Dependecy Injection" I am now looking for in this thread: http://stackoverflow.com/a/8674525/310457 (which provides a code example about the problem I am looking for a solution of)

但不是希望有人会发现,旧线与不太具体的标题,我已经创造了什么,我要寻找一个更具体的主题这一新问题。
我也将提供该线程链接到这个新问题的希望跟进有关我找了这个特定的解决方案的人。

But instead of hoping that someone will find that old thread with a less specific title, I have created this new question with a more specific subject about what I am looking for. And I will also provide a link from that thread into this new question for anyone that want to follow-up regarding this specific solution I am looking for.

推荐答案

我假设你想拥有你的ViewModels通过其构造函数的东西自动注入 - 例如某种配置对象的视图用来确定以显示。我也假设,这种做法导致错误此对象定义无参数的构造函数时MVC会尝试自动创建和绑定模型实例,从你的控制器操作的参数。让我们也再假设,我们将使用一个DI框架在运行时自动注入SiteConfig对象到我们的控制器。

I'm assuming you want to have your ViewModels automatically injected with something via their Constructor - for example some kind of configuration object that the View will use to determine what to show. I'm also assuming that this approach is causing a "No parameterless constructor defined for this object" error when MVC tries to automatically create and bind a model instance, from the arguments of your Controller Action. Let's also then assume that we will use a DI framework to inject the SiteConfig object into our Controllers automatically at runtime.

这意味着,我们必须要解决的唯一问题是如何从我们的控制器到其操作的ViewModels获得注入的对象时,他们会自动绑定。

This means that the only problem we have to solve is how to get the injected object from our Controller into its Actions' ViewModels when they are automatically bound.

所以,让我们定义一个基础模型为他人继承。

So let's define a base model for others to inherit from.

BaseViewModel

public class BaseViewModel
{
    public ISiteConfig SiteConfig { get; set; }

    public BaseViewModel(ISiteConfig siteConfig)
    {
        this.SiteConfig = siteConfig;
    }
}

现在,让我们创建一个从它继承的典范。

And now let's create a model that inherits from it.

IndexViewModel

public class IndexViewModel : BaseViewModel
{
    public string SomeIndexProperty { get; set; }

    public IndexViewModel (ISiteConfig siteConfig) : base(siteConfig) {}
}

现在让我们定义一个基本的控制器,我们的控制器将继承。

And now let's define a Base Controller that our Controllers will inherit from.

BaseController

public abstract class BaseController : Controller
{
    protected BaseController(ISiteConfig siteConfig)
    {
        _siteConfig = siteConfig;
    }

    private readonly ISiteConfig _siteConfig;

    public ISiteConfig SiteConfig
    {
        get
        {
            return _siteConfig;
        }
    }
}

现在我们定义实际控制人。

Now we define our actual controller.

的HomeController

public HomeController: BaseController
{
    public HomeController(ISiteConfig siteConfig): base(siteConfig) {}
}

假设我们使用Ninject为DI,Ninject将被配置成自动创建控制器,并通过一个具体的 ISiteConfig 对象到其在运行时构造函数。

Assuming we're using Ninject for DI, Ninject would be configured to automatically create the Controller and pass a concrete ISiteConfig object into its Constructor at runtime.

现在我们我们的行动加入到控制器。

Now we add our Action to the Controller.

index动作

public ActionResult Index(IndexViewModel model)
{
    return View(model);
}

和所以这是别人没有做任何事情,MVC将带有参数的构造函数的错误,如果你尝试调用索引操作,因为MVC无法找到一个视图模型构造不带任何参数爆炸点。

And so this is the point where without doing anything else, MVC will explode with a "Parameterless Constructor" error if you try to call the Index Action, because MVC can't find a ViewModel constructor that takes no arguments.

所以,问题的答案。我们需要覆盖缺省ModelBinder的。

And so, the answer. We need to override the default 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 默认的模型绑定:

And we need to set this as the default model binder in global.asax.cs :

protected void Application_Start()
{
    ...
    ModelBinders.Binders.DefaultBinder = new BaseViewModelBinder();
}

这就是全部。正如你所看到的,当你现在查看索引操作,MVC将使用我们的自定义模型粘合剂。它会意识到IndexViewModel从BaseViewModel派生,因此将尝试使用ISiteConfig它可以在操作的控制器发现(因为该控制器可BaseController派生)旋转起来的IndexViewModel实例。

That's all. As you can see, when you view the Index Action now, MVC will use our custom model binder. It will realise that the IndexViewModel derives from BaseViewModel, and so will attempt to spin up an IndexViewModel instance using the ISiteConfig it can find in the Action's Controller (because the Controller derives from BaseController).

这篇关于视图模型实例的构造方法注入作为一种行动方法参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆