使用基类中的参数解析构造函数参数

时间:2015-07-12 19:15:00

标签: asp.net-mvc dependency-injection castle-windsor

我有一个自定义的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做过类似的事情。我需要将哪些内容添加到安装程序才能使其正常工作?它甚至可能吗?

3 个答案:

答案 0 :(得分:1)

这里有一些选择:

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的实例运行该调用,并为其提供当前Name的{​​{1}}。通过将生活方式绑定到User,您可以验证每个请求是否会获得LifestylePerWebRequest()的自己的实例,并且不会在请求之间流失。

(您遇到的唯一边缘情况是用户在请求中进行身份验证,并且OperationWrapper需要进行调整。如果这是正常路径用例,这可能需要一些重新思考。)

然后,修改基本控制器以将该注册对象作为依赖项:

OperationWrapper

2。使用方法注入

看起来public abstract class BaseController : Controller { protected IUserService userService; protected OperationWrapper operations; public BaseController(IUserService userService, OperationWrapper operations) { this.userService = userService; this.operations = operations; } } 是某种上下文对象,有时可以将它们注入到方法而不是构造函数中。

例如,如果您的方法是:

OperationWrapper

您可以将签名修改为:

int GetTransactionId() { /* use OperationWrapper property */ }

在这种情况下,如果服务方法的一小部分使用该依赖关系,则使用它是有意义的。如果大多数(或整体)方法需要它,那么你应该采用不同的方法。

3。不要在int GetTransactionId(OperationWrapper operations) { /* use arg */ }

使用DI

在你有一个高状态的上下文对象(看起来你的OperationWrapper是)的情况下,拥有一个值传递的属性通常是有意义的。由于该对象基于某些当前线程状态,并且可以从任何子类OperationWrapper中的任何位置访问,因此它可能正确以保持您拥有的模式。

如果你不能回答“我现在无法用Controller做什么,DI会为我解决的问题?”除了“使用模式/容器”之外的任何东西,这可能是这种特殊情况的选择。

答案 1 :(得分:0)

您应该在global.asax

的Application_Start方法中设置依赖项解析器
System.Web.MVC.DependencyResolver.SetResolver(your windsor resolver)

答案 2 :(得分:0)

创建一个继承自DefaultControllerFactory的类。这样的事情会做:

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; }
    }
}

Application_Start课程的MvcApplication方法中添加以下内容:

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,因为它没有提供释放已解决的内容。