目前我正在使用DI和服务定位器模式来获取服务的实例。(请注意,服务只是通用术语 im 使用,只不过是调用 EF 存储库并执行数据操作的 C# 类。它不是WCF服务)
是否可以在视图模型中拥有服务实例?如果是,传递服务实例的正确方法是什么?
1>控制器是否应将服务实例传递给视图模型。在这种情况下,当控制器被释放时,服务会正确释放
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);
}
}
}
视图模型旨在向视图提供信息,并且应该特定于应用程序,而不是常规域。控制器应该协调与存储库、服务(我在这里对服务的定义做出一些假设)等的交互,并处理构建和验证视图模型,并且还包含确定要呈现的视图的逻辑。
通过将视图模型泄漏到"服务"层中,您将模糊您的层,现在可能的应用程序和表示特定与应关注域级职责的内容混合在一起。
只是不要混淆概念。如果您的服务处理视图模型,那么它应该是一个表示服务,并分层在实际模型之上。视图模型应该是平面和简单的 DTO,旨在与视图绑定。它们不应该是 DI 容器图的一部分,因为这会使事情复杂化,并使代码推理更加困难。
我也经历过类似的情况。我认为在视图模型中实例化域服务是可以的。域服务可以实现 IDisposable,因此我会在 get 方法中实例化它,而不是将服务创建为属性。