【问题标题】:.NET MVC3 Preferred Model Initializiation.NET MVC3 首选模型初始化
【发布时间】:2026-01-19 10:35:01
【问题描述】:

我最近一直在 MVC 中工作,我很好奇初始化我的视图模型的最佳方法是什么。我应该直接在控制器中映射它,还是应该在视图模型的构造函数中初始化属性。此外,当有列表时,这是更好的做法,因为当出现验证错误时您不必重新填充它们。

例如,如果我有以下模型:

public FooBarViewModel
{
    public int FooBarId { get; set; }
    public string SomeInitialProperty1 { get; set; }
    public string SomeInitialProperty2 { get; set; }
    public string SomeInitialProperty3 { get; set; }
    public string SomeInitialProperty4 { get; set; }
    public int FooId { get; set; }
    public int BarId { get; set; }
    public IEnumerable<Foo> Foos { get; set; }
    public IEnumerable<Bar> Bars { get; set; }
}

然后是控制器:

public MyController : Controller
{
    [HttpGet]
    public ActionResult FooBar(int foobarId)
    {
        var foobar = _fooBarRepository.GetById(foobarId);
        var model = new FooBarViewModel
                        {
                            FooBarId = foobar.Id;
                            SomeInitialProperty1 = foobar.SomeInitialProperty1;
                            SomeInitialProperty2 = foobar.SomeInitialProperty2;
                            SomeInitialProperty3 = foobar.SomeInitialProperty3;
                            SomeInitialProperty4 = foobar.SomeInitialProperty4;
                            Foos = foobar.Foos.ToList();
                            Bars = foobar.Bars.ToList();
                        }

        return View(model);
    }

    [HttpPost]
    public ActionResult FooBar(FooBarViewModel model)
    {
        if (ModelState.IsValid)
        {
             //process model
             return RedirectToAction("Index");
        }

        var foobar = _fooBarRepository.GetById(model.FoobarId);
        model.Foos = foobar.GetFoos.ToList();
        model.Bars = foobar.GetBars.ToList();
        return View(model);
    }
}

或者我应该在我的模型中这样做:

public FooBarViewModel
{
    public int FooBarId { get; set; }
    public string SomeInitialProperty1 { get; set; }
    public string SomeInitialProperty2 { get; set; }
    public string SomeInitialProperty3 { get; set; }
    public string SomeInitialProperty4 { get; set; }
    public int FooId { get; set; }
    public int BarId { get; set; }

    public IEnumerable<Foo> Foos 
    { 
        get { return _foos; }
    }
    private IEnumerable<Foo> _foos;

    public IEnumerable<Bar> Bars
    { 
        get { return _bars; }
    }
    private IEnumerable<Bar> _bars;

    public MyViewModel(FooBar foobar)
    {
        FooBarId = foobar.Id;
        SomeInitialProperty1 = foobar.SomeInitialProperty1;
        SomeInitialProperty2 = foobar.SomeInitialProperty2;
        SomeInitialProperty3 = foobar.SomeInitialProperty3;
        SomeInitialProperty4 = foobar.SomeInitialProperty4;
        _foos = foobar.Foos.ToList();
        _bars = foobar.Bars.ToList();
    }
}

然后是我的控制器:

public MyController : Controller
{
    [HttpGet]
    public ActionResult FooBar(int foobarId)
    {
        var foobar = _fooBarRepository.GetById(foobarId);
        var model = new FooBarViewModel(foobar);

        return View(model);
    }

    [HttpPost]
    public ActionResult FooBar(FooBarViewModelmodel)
    {
        if (ModelState.IsValid)
        {
             //process model
             return RedirectToAction("Index");
        }

        return View(model);
    }
}

哪个是 MVC 中的首选约定,为什么它是最佳实践?另外,为什么选择一个而不是另一个?提前致谢。

【问题讨论】:

    标签: c# .net asp.net-mvc asp.net-mvc-3


    【解决方案1】:

    默认情况下,我不相信 MVC 会使用 DependencyResolver 在回发时创建视图模型的实例。因此,它只会创建一个带有无参数构造函数的模型。这使得在构造函数中初始化对象变得不那么容易。

    您可以创建一个自定义模型绑定器,该绑定器通过 DependencyResolver 创建对象,但是您偏离了正常做法。

    我更喜欢使用 AutoMapper 初始化我的视图模型。

    【讨论】:

    • 这看起来是一个很好的解决方案,而且看起来会节省时间。我将看看在我的项目中实现这一点。谢谢。
    【解决方案2】:

    一般来说,您需要重型模型和轻型控制器,因此您需要尽可能少地使用控制器。

    您应该在视图模型中初始化 ViewModel 的一般设计模式原因?

    • DRY - 如果您有多个操作必须初始化 ViewModel,那么您就是在重复该代码,或者您将它放在控制器中的私有方法中。对我来说,如果您需要在控制器中放置私有方法,则表明代码根本不属于控制器。
    • cohesion——一般来说,Foo 对象应该知道如何从其他对象实例化 Foo 对象,因为它有责任了解自己。将该逻辑放在其他地方会降低凝聚力并引入耦合。

    【讨论】:

      【解决方案3】:

      我总是使用第二种方法,但使用“所有属性作为参数”-构造函数,而不是在构造函数中插入“Foobar”(有点违反 MVVM 模式,因为 ViewModel 应该保持独立)。

      对我来说这是最佳实践,因为您可以在视图模型中隐藏额外的逻辑,并且您可以通过使用不同的构造函数来创建不同的行为。

      【讨论】:

        【解决方案4】:

        我认为你在第二种情况下做得很好。在我看来,准备好使用的对象是该对象本身的责任。

        如果您在其他地方需要该类的另一个实例怎么办?您必须从您首先创建的地方复制初始化代码。

        【讨论】:

          最近更新 更多