如何在BaseController中初始化BaseModel

Cur*_*urt 3 c# asp.net-mvc inheritance dependency-injection model

我有一类属性,这些属性是从我在MVC应用程序的每个视图中都需要的服务设置的.

因此,我创建了一个"基本视图模型",我的视图模型将从中继承.

public class BaseModel
{
    public BaseModel()
    {
        foo = "foo value";
        bar = "bar value";
    }

    public string foo { get; set; }

    public string bar { get; set; }
}

public class HomeIndexViewModel : BaseModel
{
}
Run Code Online (Sandbox Code Playgroud)

然后我创建了一个"基本控制器",我的所有控制器将继承自:

public class BaseController : Controller
{
    public BaseController()
    {
    }
}

public class HomeController : BaseController
{
    public ActionResult Index()
    {
        HomeIndexViewModel model = new HomeIndexViewModel();
        return View(model);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是按预期工作的,我可以@Model.foo在我的视图中调用并获取foo value.

但是我不相信我应该初始化BaseModel它的构造函数的值,因为这不使用依赖注入并且将变得难以进行单元测试.

我怎样才能移动值的设置foo,并bar进入BaseController

当然我可以在其中设置值HomeController,但我宁愿从控制器中抽象出来,因为逻辑总是相同的并且会使我的所有控制器膨胀.

mus*_*fan 5

我认为问题是,你正在创建模型内的情况下采取行动,因此基本控制器没有参考对象设置的属性.

就个人而言,我可能会在基本控制器中选择一些"工厂类型"功能,负责根据需要创建模型.

像这样的东西例如:

public class BaseController : Controller
{
    public T CreateBaseModel<T>() where T : BaseModel, new()
    {
        return new T
        {
            foo = "foo value",
            bar = "bar value"
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,当您在操作中创建模型时,您可以这样做:

HomeIndexViewModel model = CreateBaseModel<HomeIndexViewModel>();
Run Code Online (Sandbox Code Playgroud)

如果由于某种原因你需要将参数传递给模型构造函数,那么你可以像这样重载:

public T CreateBaseModel<T>(params object[] args) where T : BaseModel
{
    T model = (T)Activator.CreateInstance(typeof(T), args);
    model.foo = "foo";
    return model;
}

HomeIndexViewModel model = CreateBaseModel<HomeIndexViewModel>(param1, param2, etc);
Run Code Online (Sandbox Code Playgroud)

替代

上述方法的主要好处是您可以访问操作代码中的foobar属性.但是,如果您不关心这一点并且只需要在"视图"页面中可以访问这些值,那么您可以覆盖该OnActionExecuted方法并在其中应用这些值.这种方法的好处是您不需要改变在动作中创建模型的方式......

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    BaseModel model = filterContext.Controller.ViewData.Model as BaseModel;
    if (model != null)
    {
        model.foo = "foo value";
        model.bar = "bar value";
    }

    base.OnActionExecuted(filterContext);
}
Run Code Online (Sandbox Code Playgroud)

进行null检查意味着它只会尝试应用继承的模型的值BaseModel,这意味着您仍然可以毫无顾虑地使用其他模型.

使用这种方法,您的操作代码可以追溯到最初的方式:

HomeIndexViewModel model = new HomeIndexViewModel();
return View(model);
Run Code Online (Sandbox Code Playgroud)

  • @Steven:感谢您的编辑,不知道这一点,但看起来不错! (3认同)