【发布时间】:2014-07-28 18:33:59
【问题描述】:
我有 3 个服务组件,一个负责某种数据序列化的低级服务,一个负责协调保存/加载的中间服务,一个负责 API 发布的 MVC 控制器。
这 3 个组件中的每一个在逻辑上都指向它“下方”的另一个。中间服务有另一个参数,它在运行时是已知的,基于请求数据。从这 3 个组件中,控制器和中间服务由类表示(引入接口没有意义,因为没有什么可模拟的),并且最低级别由接口表示,使其可用于对中间服务进行单元测试或控制器。我想使用 DI(特别是 Ninject)来构建我的控制器类。我的问题是是否存在处理这种情况的任何最佳实践。目前我看到了两种实现方式。 (为了清楚起见,省略了验证和正确的实现。)
首先,这里是中间服务和底层接口的示例实现。
public interface ISerializer {
void Serialize(object data);
}
public class MyService {
private string _dataId;
private ISerializer _serializer;
public MyService(string dataId, ISerializer serializer) {
_serializer = serializer;
_dataId = dataId;
}
public bool CanProcess(MyDTO data) {
...
}
public void DoSomeProcessing(MyDTO data) {
...
}
}
版本一:将整个中间服务作为工厂注入到控制器中
public class MyController : Controller {
private Func<string, MyService> _myServiceFactory;
public MyController(Func<string, MyService> myServiceFactory) {
_myServiceFactory = myServiceFactory;
}
...
[HttpPost]
public JsonResult Process(string dataId, MyDTO model) {
using (var myService = _myServiceFactory(dataId)) {
...
if (myService.CanProcess(model))
myService.DoSomeProcessing(model);
...
return Json("ok");
}
}
}
版本2:直接将底层接口注入控制器,“手动”实例化中间服务。
public class MyController : Controller {
private ISerializer _serializer;
public MyController(ISerializer serializer) {
_serializer = serializer;
}
...
[HttpPost]
public JsonResult Process(string dataId, MyDTO model) {
using (var myService = new MyService(dataId, _serializer) {
...
if (myService.CanProcess(model))
myService.DoSomeProcessing(model);
...
return Json("ok");
}
}
}
哪个更合适,还是我应该选择完全不同的解决方案?
【问题讨论】:
-
为什么不让 Ninject 处理所有事情呢?只要您提供所有绑定引用,Ninject 就会在控制器加载时初始化控制器所需的内容,并一直遵循依赖链。
-
@ChrisPratt 是的,我会这样做,但我在 MyService 上有那个棘手的运行时构造函数参数。看代码的时候,我要更喜欢工厂版了……
-
这取决于。即使依赖项是值类型,如果你能告诉它如何做,Ninject 也可以解决它。您只需要定义一个可以以某种方式返回此值的方法并告诉 Ninject 使用它。但是,如果这是您真正无法在更高级别解决的问题,那么依赖注入(至少对于您的控制器)无论如何都是不可能的。总而言之,这是一个架构问题。
-
正如您在代码中看到的那样,该值来自请求。可能我有更高层次的设计问题,我正在考虑。
标签: c# asp.net-mvc design-patterns dependency-injection ninject