是不是从ViewModel实践调用业务逻辑

时间:2014-04-10 05:41:00

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

我正在开发一个大型ASP.NET MVC项目(大约15个独立的项目)。我们使用Facade设计模式来调用业务逻辑以及其他项目。

问题:在MVC应用程序中从ViewModel调用Facade是最佳做法吗?

我使用单个Facade实例来调用所有函数。我为每个Action创建一个ViewModel,并使用ViewModel中的数据填充它。这些结果使ViewModel更大,但Controller Action变得更薄,因为我们现在正在ViewModel中完成工作。在ViewModel构造函数中,我传递了Facade实例,并从业务逻辑层中获取所需的内容。

public class MyViewModel
{
    private Facade _Facade;
    public IEnumerable<SomeModel> Collection { get; set; }
    public IEnumerable<SelectListItem> Years { get; set; }
    public IEnumerable<SelectListItem> Quarters { get; set; }
    public int SelectedYear { get; set; }
    public int SelectedQuarter { get; set; }


     public BottomUpForecastViewModel(EXFacade facade)
    {
        this._Facade = facade;
        this.Years = GetFinancialYears();
        this.Quarters = GetFinancialQuarters();
        this.SelectedYear = DateTime.Now.Year;
        this.SelectedQuarter = TimePeriods.GetQuarterNoForDate(DateTime.Now);
        Collection = GetMonthlyCollection(SelectedYear, SelectedQuarter);// Take data     from the _Facade(call facade)

    }

}

  public class MyController : Controller
  {


    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult BottomUpForecast()
    {

        return View(new MyViewModel(facade));
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult BottomUpForecast(MyViewModel model)
    {

        return View();

    }

}

这是好习惯吗?

考虑到我们不需要担心依赖关系,您是否建议采用更好的方法?

更新:我发现了一篇有趣的文章,讲述如何让控制器精益求精“让它们节食”: http://lostechies.com/jimmybogard/2013/12/19/put-your-controllers-on-a-diet-posts-and-commands/ **

4 个答案:

答案 0 :(得分:10)

你的想法是正确的。从View Model调用业务逻辑是完全可以接受的。我一直这样做。

不幸的是,您当前的实现与具体类型紧密相关。你可以使用一点抽象重构:

在您的业务层中,创建一个接口,IEXFacade传递绑定您的对象并传递给您的ViewModel:

public interface IEXFacade
{
   public IEnumerable<SomeModel> GetMonthlyCollection(int SelectedYear, int SelectedQuarter);
   public IEnumerable<SelectListItem> GetFinancialYears();
   public IEnumerable<SelectListItem> GetFinancialQuarters();
   public int getSelectedYear();
   public int getSelectedQuarter(DateTime dateTime);
}

,您的EXFacade定义如下所示:

public class EXFacade : IEXFacade
{
   private TimePeriods _timePeriods = new TimePeriods();

   public int getSelectedYear()
   {
       return DateTime.Now.Year;
   }

   public int getSelectedQuarter (DateTime dateTime)
   {
       return _timePeriods.GetQuarterNoForDate(dateTime);
   }


   public IEnumerable<SomeModel> GetMonthlyCollection()
   {
           ....
           return MonthlyCollection;
   }

   public IEnumerable<SelectListItem> GetFinancialYears();
   {
           ....
           return MonthlyCollection;
   }

   public IEnumerable<SelectListItem> GetFinancialQuarters();
   {
           ....
           return MonthlyCollection;
   }

}

现在,您的视图模型将采用IEXFacade并且​​更能容忍更改

public class MyViewModel
{
     MyViewModel(IEXFacade facade)
     {
        Years = facade.GetFinancialYears();
        Quarters = facade.GetFinancialQuarters();
        SelectedYear = facade.getSelectedYear();
        SelectedQuarter = facade.getSelectedQuarter (DateTime.Now);
        Collection = facade.GetMonthlyCollection(SelectedYear, SelectedQuarter);
    }


    //Keeping the Facade Object seems extraneous (unless I'm missing something)
    //private Facade _Facade;
    public IEnumerable<SomeModel> Collection { get; set; }
    public IEnumerable<SelectListItem> Years { get; set; }
    public IEnumerable<SelectListItem> Quarters { get; set; }
    public int SelectedYear { get; set; }
    public int SelectedQuarter { get; set; }
}

目标是通过传递接口来解除对EXFacade类的特定实现的依赖。现在,您的EXFacade方法逻辑可以在不破坏视图模型的情况下进行更改。只要接口(属性和签名)保持不变。


<强>结论:

我不偏向于直接从我的ViewModel调用逻辑,而不是我的Controller。但是,它通常更方便,因为它节省了一步。相反,直接注入模型的逻辑不如将其合并到控制器中那么明显。但关于&#34; Fat Controllers&#34; vs&#34; Fat Models&#34;非常平庸,我不认为任何一方更正确。

更重要的是要了解Facade Pattern是你&#34; Chatty&#34;之间的接口。逻辑层和您的表示层。为了抽象和解耦,模式需要一个接口。只要使用界面抽象Facade,就可以使用像NInject这样的IOC容器进一步解除耦合,将Facade注入控制器或模型中。

我强烈建议在像这样的大型项目中使用依赖注入模式。

答案 1 :(得分:8)

视图模型是视图的模型。它应包含数据(模型)以及将数据移入和移出视图所需的任何逻辑。它不应该知道任何其他层。它甚至不应该依赖于控制器,更不用说下面的任何东西了。控制器的作用是填充该视图模型,以便控制器调用业务逻辑。

答案 2 :(得分:7)

如果将业务逻辑放在ViewModel中,您将打破MVC模式。构建视图是控制器的工作,而不是通过接收依赖性构建自身的视图。

ViewModel应该不了解其他层(视图和控制器),从而促进松散耦合的架构。

如果ViewModel变得太大,您可以创建辅助方法或类,仅用于构建ViewModel。

public class MyController : Controller
{
    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult BottomUpForecast()
    {
        return View(this.GetMyViewModel());
    }


    private MyViewModel GetMyViewModel()
    {
        var viewModel = new MyViewModel()
        {
            Years = this.facade.GetFinancialYears();
            Quarters = this.facade.GetFinancialQuarters();
            SelectedYear = DateTime.Now.Year;
            SelectedQuarter = this.facade.TimePeriods.GetQuarterNoForDate(DateTime.Now);
            Collection = this.facade.GetMonthlyCollection(SelectedYear, SelectedQuarter);
        }

        return viewModel;
    }
}

// Thin ViewModel
public class MyViewModel
{
    public IEnumerable<SomeModel> Collection { get; set; }
    public IEnumerable<SelectListItem> Years { get; set; }
    public IEnumerable<SelectListItem> Quarters { get; set; }
    public int SelectedYear { get; set; }
    public int SelectedQuarter { get; set; }
}

有关此主题的有趣讨论:https://stackoverflow.com/a/1464030/1027250

答案 3 :(得分:1)

只需添加到@Yorro帖子中,MVVM实际上使用此模式,其中VM负责所有此类活动。最好将控制器用于MVC中的此类操作。