【问题标题】:MVC4 Best practices, where to include LogicMVC4 最佳实践,在哪里包含逻辑
【发布时间】:2013-12-23 00:30:11
【问题描述】:

我正在学习 MVC,但我怀疑我是否以低效的方式编写控制器和模型。

我做了以下例子来尝试说明我的情况:

我倾向于将我的大部分逻辑放在我的模型中。一个简单的例子如下:

  public partial class TestModel
  {
    public List<TestObject> ReportData
    {
      get
      {
        TestRepository rep = new TestRepository ();
        return rep.GetData(IdObject);
      }
    }

    public int IdObject{ get; set; }
   }

一旦设置了有效的 IdObject,此模型就会生成 ReportData。这种方法的一个优点是它可以导致更小的操作方法。

  public class TestController
  {
    public ActionResult Test1()
    {
      return View(new TestModel());
    }

    [HttpGet]
    public ActionResult Test2()
    {
      return View(new TestModel());
    }

    [HttpPost]
    public ActionResult Test3(TestModel model)
    {
      return View(model);
    }
}

相对于:

  public class TestController
  {
    public ActionResult Test1()
    {
      TestModel model = new TestModel();
      TestRepository rep = new TestRepository ();
      model.ReportData = rep.GetData(IdObject);
      return View(model);
    }

    [HttpGet]
    public ActionResult Test2()
    {
      TestModel model = new TestModel();
      TestRepository rep = new TestRepository ();
      model.ReportData = rep.GetData(IdObject);
      return View(model);
    }

    [HttpPost]
    public ActionResult Test3(TestModel model)
    {
      TestRepository rep = new TestRepository ();
      model.ReportData = rep.GetData(IdObject);
      return View(model);
    }
}

所以最后我通过在我的模型中保留尽可能多的逻辑来减少代码重用。 在我看来,另一个好处是我可以使大多数属性只读而忘记某些东西或有人覆盖它们(opened colsed 原则)。

我在使用这种方法时遇到的问题是,有时计算属性的成本可能很高(它们可能来自数据库或可能是处理器密集型计算),并且有时计算会进行多次。

例如,如果我的视图包含以下代码:

@if (Model.ReportData.Count() > 0)
                {
                    foreach (var item in Model.ReportData)
                    {
                        item
                    }
}

如何确保数据不会反复计算?对于如何更好地编码我的模型和控制器,是否有一些建议的最佳实践?

【问题讨论】:

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


    【解决方案1】:

    一般来说,逻辑应该在控制器中,而不是模型中。您可以让控制器调用共享私有方法以避免重复自己。示例:

    型号:

      public partial class TestModel
      {
        public List<TestObject> ReportData { get; set; }
        public int IdObject{ get; set; }
      }
    

    控制器:

    public class TestController
      {
        public ActionResult Test1()
        {
          return View(CreateTestModel());
        }
    
        [HttpGet]
        public ActionResult Test2()
        {
          return View(CreateTestModel());
        }
    
        [HttpPost]
        public ActionResult Test3(TestModel model)
        {
          return View(CreateTestModel());
        }
    
        private TestModel CreateTestModel() {
          TestModel model = new TestModel();
          TestRepository rep = new TestRepository ();
          model.ReportData = rep.GetData(IdObject);
          return model
        }
    }
    

    这也解决了您的视图访问属性时没有计算任何数据的问题,因为您的控制器填充属性,因此从模型访问它们不会导致重新计算。

    【讨论】:

    • 好答案,+1 - 可能还值得详细说明为什么逻辑属于控制器而不是视图模型。
    • 我会真正受益于为什么逻辑应该在控制器中的解释。我四处搜索,似乎有很多讨论支持这两种方法。例如stackoverflow.com/questions/235233/… 为胖模型和瘦控制器提供了一个案例
    • 我使用模型作为数据的描述,控制器负责更新模型。然而,在这种方法中,您最终会得到巨大的控制器,因此我使用存储库模式(或数据层)。
    【解决方案2】:

    到目前为止,我在 ASPConf2012 上的 Steve Smith ASP.NET MVC Solution Best Practices Presentation 中看到了这个问题的最佳答案。虽然看起来像是“长视频”,但非常值得。

    在其中,Smith 采用现有解决方案并重构代码以遵循“洋葱架构”,并向您展示哪些代码工件属于 MVC 架构中的哪个位置。查看“之前”和“之后”代码库有助于理解“为什么”。

    Here's the source code Smith 在其演示文稿中介绍的示例应用程序。

    【讨论】:

    • 感谢您的贡献。我会在午餐时查看视频!
    猜你喜欢
    • 1970-01-01
    • 2021-06-21
    • 2021-11-08
    • 1970-01-01
    • 2016-06-17
    • 1970-01-01
    • 1970-01-01
    • 2017-01-19
    • 1970-01-01
    相关资源
    最近更新 更多