我有一个自定义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()并将其注入到BaseControllerScenarioService中。 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运行该调用,并为该实例提供当前NameUser。通过将生活方式绑定到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做什么”的问题,除了“使用模式/容器”之外,其他任何选项都可以用于这种特殊情况。

10-04 12:05