【问题标题】:In MVC can ViewModels access service layer?在 MVC 中 ViewModels 可以访问服务层吗?
【发布时间】:2015-06-11 16:35:50
【问题描述】:

目前我正在使用 DI 和服务定位器模式来获取服务实例。 (请注意,Service 只是我使用的通用术语,只不过是调用 EF 存储库并执行数据操作的 C# 类。它不是 WCF 服务)

可以在 ViewModel 中有 Service 实例吗?如果是,传递服务实例的正确方法是什么?

1>控制器是否应该将服务实例传递给 ViewModel。在这种情况下,当控制器被处理时,服务会被正确处理

2>或者 ViewModel 应该使用 DI 和服务定位器获取服务实例。在这种情况下,服务将如何处理?

基础控制器

public class BaseController:Controller
{
   private MyDomainService _myDomainServiceInstance = null;

    protected MyDomainService MyDomainServiceInstance
    {
        get
        {
            if (_myDomainServiceInstance == null)
            {
                _myDomainServiceInstance = DefaultServiceLocator.Instance.GetInstance<MyDomainService>();
            }

            return _myDomainServiceInstance;
        }
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        if (_myDomainServiceInstance != null)
        {
            _myDomainServiceInstance.Dispose();
        }
    }
}

控制器

public class MyController:BaseController
{
    public ActionResult DoSomething()
    {
        var model = new SummaryVM(MyDomainServiceInstance);
    }
}

视图模型

public class SummaryVM
{
    MyDomainService _myDomainService = null;        

    public SummaryVM(MyDomainService myDomainService)
    {
        //Approache 1: Controller is passing the service instance
        _myDomainService = myDomainService;
    }

    public SummaryVM()
    {
        //Aprooche 2: Use DI & Service locator pattern to get the instance
        _myDomainService = DefaultServiceLocator.Instance.GetInstance<MyDomainService>();
    }

    public int[] SelectedClients { get; set; }

    public string[] SelectedStates { get; set; }


    public IEnumerable<Clients> PreSelectedClients
    {
        get
        {
            if (SelectedClients == null || !SelectedClients.Any())
            {
                return new List<AutoCompletePreSelectedVM>();
            }

            return _myDomainService.GetClients(SelectedClients);
        }
    }
}

【问题讨论】:

    标签: asp.net-mvc viewmodel domainservices


    【解决方案1】:

    视图模型旨在提供与视图之间的信息,并且应该特定于应用程序,而不是一般域。控制器应该协调与存储库、服务(我在这里对服务的定义做出一些假设)等的交互,并处理构建和验证视图模型,并且还包含确定要呈现的视图的逻辑。

    通过将视图模型泄漏到“服务”层,您正在模糊您的层,现在可能会将特定于应用程序和表示的内容与应该关注域级职责的内容混合在一起。

    只是不要混淆概念。如果您的服务处理视图模型,那么它应该是一个表示服务,并在实际模型之上分层。 视图模型应该是扁平且简单的 DTO,旨在与视图绑定。它们不应该是 DI 容器图的一部分,因为这会使事情复杂化并使代码的推理更加困难。

    【讨论】:

    • 我不会将视图模型泄漏到“服务”层,因此服务不会访问视图模型。事实上它的另一种方式。 ViewModel 正在访问服务。 (请参见上面的代码) ViewModels 位于 Web 项目中 Controllers 旁边的“Models”文件夹中。而域服务是一个单独的库。 Web 项目引用了域服务。我的问题就像控制器,可以查看模型访问服务吗?如果是,那么我应该在 ViewModel 中的哪里处理服务。
    • 我认为 ViewModel 需要访问服务/存储库的另一种情况是,当您想使用 IValidatableObject 执行服务器端模型验证并需要在 Validate 方法中查询数据库时。
    【解决方案2】:

    我也经历过类似的情况。我认为可以在视图模型中实例化域服务。域服务可以实现 IDisposable,所以我会在 get 方法中对其进行实例化,而不是将服务创建为属性。

    【讨论】:

    • 是的,域服务已经有 IDisposable。但是,在 Get 中实例化是一种选择,如果我有多个“gets”属性,那么它将创建新实例并为每个 get 处理它。这意味着在内部它将创建 SQL 连接并在每个“get”上进行处理
    • 我明白你的意思并同意。如果您封装 PreSelectedClients,封装所有其他只读列表,并创建一个填充这些字段的方法。您的控制器将在返回视图模型以查看之前调用此方法。在这种方法中,您只能将服务实例化一次。
    猜你喜欢
    • 1970-01-01
    • 2011-02-17
    • 2013-10-30
    • 2012-11-08
    • 1970-01-01
    • 2015-07-13
    • 2015-01-11
    • 1970-01-01
    • 2011-10-22
    相关资源
    最近更新 更多