c# - CaSTLe Windsor - 注入(inject) IActionInvoker 实现问题

标签 c# dependency-injection castle-windsor

我正在尝试使用 this 中的方法文章,但我遗漏了一些东西 - 我目前在 WindsorControllerFactory.GetControllerInstance 中遇到错误,因为它试图解析 IActionInvoker,因为 WindsorActionInvoker 依赖于 IWindsorContainer。

鉴于 WindsorControllerFactory 已经有对 IWindsorContainer 的引用,我可以传递该引用吗?如果是这样 - 怎么样?我发现的唯一示例是关于将值类型作为构造函数参数传递的,而不是引用类型。

我觉得我遗漏了一些明显的东西......

当前设置如下: 在 Global.asax Application_Start 中,我调用了以下方法:

 protected virtual IWindsorContainer InitializeServiceLocator()
    {
        IWindsorContainer container = new WindsorContainer();
        ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container));

        container.RegisterControllers(typeof(HomeController).Assembly);
        ComponentRegistrar.AddComponentsTo(container);

        return container;
    }

组件注册器:

 public static void AddComponentsTo(IWindsorContainer container) 
 {
      //add other components.....

      container.AddComponentLifeStyle<IActionInvoker, WindsorActionInvoker>(LifestyleType.PerWebRequest);

 }

WindsorActionInvoker:

public class WindsorActionInvoker : ControllerActionInvoker, IActionInvoker
{
    readonly IWindsorContainer container;

    public WindsorActionInvoker(IWindsorContainer container)
    {
        this.container = container;
    }

    protected override ActionExecutedContext InvokeActionMethodWithFilters(
            ControllerContext controllerContext,
            IList<IActionFilter> filters,
            ActionDescriptor actionDescriptor,
            IDictionary<string, object> parameters)
    {
        foreach (IActionFilter actionFilter in filters)
        {
            container.Kernel.InjectProperties(actionFilter);
        }
        return base.InvokeActionMethodWithFilters(controllerContext, filters, actionDescriptor, parameters);
    }
}

温莎 Controller 工厂:

 public class WindsorControllerFactory : DefaultControllerFactory
{
    private readonly IWindsorContainer container;

    public WindsorControllerFactory(IWindsorContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
        this.container = container;
    }

    public override void ReleaseController(IController controller)
    {
        var disposable = controller as IDisposable;

        if (disposable != null)
        {
            disposable.Dispose();
        }

        this.container.Release(controller);
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            return base.GetControllerInstance(requestContext, controllerType);
        }

        var controller = this.container.Resolve(controllerType) as Controller;

        if (controller != null)
        {
            controller.ActionInvoker = this.container.Resolve<IActionInvoker>(this.container);
        }

        return controller;
    }
}

Update

我错过了一个微妙之处:我试图将此行为用于以下目的:

public class CustomAuthorize : AuthorizeAttribute {...}

它没有实现 IActionFilter

向 WindsorActionInvoker 添加了以下内容:

 protected override AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)
    {
        foreach (IAuthorizationFilter authorizeFilter in filters)
        {
            this.kernel.InjectProperties(authorizeFilter);
        }
        return base.InvokeAuthorizationFilters(controllerContext, filters, actionDescriptor);
    }

这现在可以按要求工作了。感谢 Cristiano,因为正是对他友善提供的代码的分析让我走上了正确的道路。

最佳答案

全局.asax

private static void bootstrapContainer()
{
    container = new WindsorContainer()
        .Install(FromAssembly.This());
    var controllerFactory = new WindsorControllerFactory(container.Kernel);

    ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}

安装器/灌装容器

public class ControllersInstaller : IWindsorInstaller
{
    #region IWindsorInstaller Members

    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component.For<WpRegistration.Web.Filters.AgencyAuthorize>().LifeStyle.Transient);
        container.Register(Component.For<IActionInvoker>().ImplementedBy<WindsorExtensions.Mvc.WindsorActionInvoker>().LifeStyle.Transient);

        container.Register(AllTypes.FromThisAssembly()
                            .BasedOn<IController>()
                            .If(Component.IsInSameNamespaceAs<HomeController>())
                            .If(t => t.Name.EndsWith("Controller"))
                            .Configure((c => c.LifeStyle.Transient)));
    }

    #endregion
}

温莎 Controller 工厂

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

using Castle.MicroKernel;

public class WindsorControllerFactory : DefaultControllerFactory
{
    private readonly IKernel kernel;

    public WindsorControllerFactory(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public override void ReleaseController(IController controller)
    {
        kernel.ReleaseComponent(controller);
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
        }

    IController iController = (IController)kernel.Resolve(controllerType);

    // new code    
    if (iController is Controller)    
    {
        ((Controller)iController).ActionInvoker = kernel.Resolve<IActionInvoker>();
    }

    return iController;
    }
}

温莎 Action 调用者

namespace WindsorExtensions.Mvc
{

    public class WindsorActionInvoker : ControllerActionInvoker
    {
        readonly IKernel kernel;
        public WindsorActionInvoker(IKernel kernel) 
        { 
            this.kernel = kernel; 
        }
        protected override ActionExecutedContext InvokeActionMethodWithFilters(
            ControllerContext controllerContext
            , IList<IActionFilter> filters
            , ActionDescriptor actionDescriptor
            , IDictionary<string, object> parameters)
        {
            foreach (IActionFilter actionFilter in filters)
            {
                kernel.InjectProperties(actionFilter);
            }
            return base.InvokeActionMethodWithFilters(controllerContext, filters, actionDescriptor, parameters);
        }
    }

    public static class WindsorExtension 
    { 
        public static void InjectProperties(this IKernel kernel, object target) 
        { 
            var type = target.GetType(); 
            foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) 
            { 
                if (property.CanWrite && kernel.HasComponent(property.PropertyType)) 
                { 
                    var value = kernel.Resolve(property.PropertyType); 
                    try { property.SetValue(target, value, null); } 
                    catch (Exception ex) 
                    { 
                        var message = string.Format("Error setting property {0} on type {1}, See inner exception for more information.", property.Name, type.FullName);
                        throw new ComponentActivatorException(message, ex); 
                    }
                }
            }
        }
    }
}

机构授权属性

namespace WpRegistration.Web.Filters 
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public sealed class AgencyAuthorize : ActionFilterAttribute
    {
        CurrentUserService _currentUserSvc;
        public AgencyAuthorize() { }

        public CurrentUserService Service
        {
            get { return _currentUserSvc; }
            set
            {
                this._currentUserSvc=value;
            }
        }

关于c# - CaSTLe Windsor - 注入(inject) IActionInvoker 实现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6622613/

相关文章:

dependency-injection - xml配置还是通过代码配置?

c# - 使用 Ninject 确保 Controller 具有无参数公共(public)构造函数

inversion-of-control - CaSTLe Windsor 注册组件的默认生活方式可以更改吗?

c# - 来自客户端的 SignalR 多个并发调用

c# - PredicateBuilder 返回所有用户 predicate.Or

使用案例类/伴随对象模式时的 Scala 依赖注入(inject)

caSTLe-windsor - Windsor with composite WPF 二月发布 (Prism 2)

c# - Akka.NET 和 MVVM

c# - DotNetZip 卡住我的应用程序?

c# - Twitter 登录表单中的 ui_metrics