使用 base class 中的参数解析构造函数参数
Resolve constructor argument with parameter from base class
我有一个自定义的 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;
}
}
这是我的温莎安装程序。
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 做过类似的事情。我需要在安装程序中添加什么才能使其正常工作?有可能吗?
您应该在 global.asax
的 Application_Start 方法中设置依赖解析器
System.Web.MVC.DependencyResolver.SetResolver(your windsor resolver)
创建一个继承自 DefaultControllerFactory
的 class。这样的事情会做:
public class WindsorControllerFactory : DefaultControllerFactory
{
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(
404,
String.Format(
CultureInfo.CurrentCulture,
"The controller for path '{0}' was not found or does not implement IController.",
requestContext.HttpContext.Request.Path
)
);
}
return (IController)_kernel.Resolve(controllerType);
}
public override void ReleaseController(IController controller)
{
Kernel.ReleaseComponent(controller);
}
private readonly IKernel _kernel;
private IKernel Kernel
{
get { return _kernel; }
}
}
在 MvcApplication
class 的 Application_Start
方法中添加以下内容:
var container = new WindsorContainer();
container.Install(FromAssembly.This());
ControllerBuilder.Current.SetControllerFactory(
new WindsorControllerFactory(container.Kernel)
);
这应该可以与您现有的安装程序一起使用,并让您到达 Windsor 开始为您解决依赖关系的地步。您可能需要填补一些空白,但您会明白这一点的。
我大量借用了:https://github.com/castleproject/Windsor/blob/master/docs/mvc-tutorial-intro.md
谨慎使用 IDependencyResolver,因为它不会发布已解决的问题。
这里有几个选项:
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
时,它都会 运行 调用一个实例 if 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。根本不要对 OperationWrapper
使用 DI
在你有一个高度有状态的上下文对象的情况下(看起来你的 OperationWrapper
是),通常有一个 属性 的值被传递是有意义的。由于该对象基于某些当前线程状态,并且可以从任何子类中的任何地方访问 Controller
,因此可能正确 只保留您拥有的模式。
如果您无法用 "use the pattern/container," 以外的任何其他方式回答问题 "What am I unable to do with OperationWrapper
now that DI is going to solve for me?",这可能是针对这种特殊情况的选择。
我有一个自定义的 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;
}
}
这是我的温莎安装程序。
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 做过类似的事情。我需要在安装程序中添加什么才能使其正常工作?有可能吗?
您应该在 global.asax
的 Application_Start 方法中设置依赖解析器System.Web.MVC.DependencyResolver.SetResolver(your windsor resolver)
创建一个继承自 DefaultControllerFactory
的 class。这样的事情会做:
public class WindsorControllerFactory : DefaultControllerFactory
{
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(
404,
String.Format(
CultureInfo.CurrentCulture,
"The controller for path '{0}' was not found or does not implement IController.",
requestContext.HttpContext.Request.Path
)
);
}
return (IController)_kernel.Resolve(controllerType);
}
public override void ReleaseController(IController controller)
{
Kernel.ReleaseComponent(controller);
}
private readonly IKernel _kernel;
private IKernel Kernel
{
get { return _kernel; }
}
}
在 MvcApplication
class 的 Application_Start
方法中添加以下内容:
var container = new WindsorContainer();
container.Install(FromAssembly.This());
ControllerBuilder.Current.SetControllerFactory(
new WindsorControllerFactory(container.Kernel)
);
这应该可以与您现有的安装程序一起使用,并让您到达 Windsor 开始为您解决依赖关系的地步。您可能需要填补一些空白,但您会明白这一点的。
我大量借用了:https://github.com/castleproject/Windsor/blob/master/docs/mvc-tutorial-intro.md
谨慎使用 IDependencyResolver,因为它不会发布已解决的问题。
这里有几个选项:
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
时,它都会 运行 调用一个实例 if 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。根本不要对 OperationWrapper
使用 DI
在你有一个高度有状态的上下文对象的情况下(看起来你的 OperationWrapper
是),通常有一个 属性 的值被传递是有意义的。由于该对象基于某些当前线程状态,并且可以从任何子类中的任何地方访问 Controller
,因此可能正确 只保留您拥有的模式。
如果您无法用 "use the pattern/container," 以外的任何其他方式回答问题 "What am I unable to do with OperationWrapper
now that DI is going to solve for me?",这可能是针对这种特殊情况的选择。