我有一个自定义ASP.NET MVC控制器,该控制器从用户服务中检索操作。我想使用依赖项注入将操作属性传递给方案服务。
public abstract class BaseController : Controller {
protected IUserService userService;
public OperationWrapper operations { get; private set; }
public BaseController(IUserService userService) {
this.userService = userService;
this.operations = userService.GetOperations(HttpContext.Current.User.Identity.Name);
}
}
public abstract class ScenarioController : BaseController {
protected IScenarioService scenarioService;
public ScenarioController(IScenarioService scenarioService, IUserService userService)
: base(userService) {
this.scenarioService = scenarioService;
}
}
public class ScenarioService : IScenarioService {
private OperationWrapper operations;
public ScenarioService(OperationWrapper operations) {
this.repo = repo;
this.operations = operations;
}
}
这是我的Windsor安装程序。
public class Installer : IWindsorInstaller {
public void Install(IWindsorContainer container, IConfigurationStore store) {
container.Register(Classes.FromThisAssembly()
.BasedOn<IController>());
container.Register(Classes.FromThisAssembly()
.Where(x => x.Name.EndsWith("Service"))
.WithService.DefaultInterfaces()
.LifestyleTransient());
}
}
我很确定几年前已经对Ninject做过类似的事情。为了使这项工作有效,我需要添加什么到安装程序?可能吗
最佳答案
这里有一些选择:
1.使用LifeStylePerWebRequest()
和UsingFactoryMethod()
首先,您可以将OperationWrapper
注册为LifestylePerWebRequest()
并将其注入到BaseController
和ScenarioService
中。 Windsor允许您使用工厂方法注册依赖关系以创建依赖关系,该方法又可以调用已注册的其他服务。
container.Register(Component.For<OperationWrapper>()
.LifestylePerWebRequest()
.UsingFactoryMethod(kernel =>
{
var userService = kernel.Resolve<IUserService>();
try
{
return userService.GetOperations(
HttpContext.Current.User.Identity.Name);
}
finally
{
kernel.ReleaseComponent(userService);
}
}));
因此,每次要求温莎(Windsor)输入
OperationWrapper
时,它将针对实例IUserService
运行该调用,并为该实例提供当前Name
的User
。通过将生活方式绑定到LifestylePerWebRequest()
,您可以验证每个请求将获得其自己的OperationWrapper
实例,并且不会在请求之间流血。(您遇到的唯一一种极端情况是,用户在请求中途已通过身份验证,因此需要调整
OperationWrapper
。如果这是常规路径用例,则可能需要重新考虑。 )然后,修改您的基本控制器以将该注册对象作为依赖项:
public abstract class BaseController : Controller {
protected IUserService userService;
protected OperationWrapper operations;
public BaseController(IUserService userService, OperationWrapper operations) {
this.userService = userService;
this.operations = operations;
}
}
2.使用方法注入
看起来
OperationWrapper
是某种上下文对象,有时可以将其注入到方法中而不是构造函数中。例如,如果您的方法是:
int GetTransactionId() { /* use OperationWrapper property */ }
您可以将签名修改为:
int GetTransactionId(OperationWrapper operations) { /* use arg */ }
在这种情况下,如果您的服务方法的一小部分使用该依赖关系,则使用它是有意义的。如果大多数(或全部)方法都需要它,那么您可能应该走另外一条路。
3.完全不要将DI用于
OperationWrapper
在具有高度状态的上下文对象(看起来像您的
OperationWrapper
是)的情况下,通常有意义的是拥有一个其值被传递的属性。由于该对象基于某种当前线程状态,并且可以从任何子类Controller
中的任何位置进行访问,因此仅保留您拥有的模式可能是正确的。如果您不能回答“ DI将为我解决的问题,我现在又不能与
OperationWrapper
做什么”的问题,除了“使用模式/容器”之外,其他任何选项都可以用于这种特殊情况。