温莎城堡 - 注射IActionInvoker执行问题 [英] Castle Windsor - Injecting IActionInvoker Implementation Issue

查看:241
本文介绍了温莎城堡 - 注射IActionInvoker执行问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用的方法从的这个文章,但我失去了一些东西 - 我目前得到,当它试图解决IActionInvoker因为WindsorActionInvoker内WindsorControllerFactory.GetControllerInstance错误对IWindsorContainer依赖



由于WindsorControllerFactory已经具备IWindsorContainer一个参考,我能通过在参考?如果是的话 - 如何?我发现的唯一的例子是有关传递值​​类型为构造函数的参数,而不是引用类型。



我感觉我失去了一些东西明显...



当前设置如下:
在Global.asax中的Application_Start我叫下面的方法:

 受保护的虚拟IWindsorContainer InitializeServiceLocator()
{
IWindsorContainer集装箱=新WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(新WindsorControllerFactory(容器));

container.RegisterControllers(typeof运算(HomeController中).Assembly);
ComponentRegistrar.AddComponentsTo(容器);

返回容器中;
}



ComponentRegistrar:

 公共静态无效AddComponentsTo(IWindsorContainer容器)
{
//添加其他成分.....

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

}



WindsorActionInvoker:

 公共类WindsorActionInvoker:ControllerActionInvoker,IActionInvoker 
{
只读IWindsorContainer容器;

公共WindsorActionInvoker(IWindsorContainer容器)
{
this.container =容器;
}

保护覆盖ActionExecutedContext InvokeActionMethodWithFilters(
ControllerContext controllerContext,
的IList< IActionFilter>过滤器,
ActionDescriptor actionDescriptor,
的IDictionary<字符串,对象>参数)
{
的foreach(IActionFilter actionFilter滤镜)
{
container.Kernel.InjectProperties(actionFilter);
}
返回base.InvokeActionMethodWithFilters(controllerContext,过滤器,actionDescriptor,参数);
}
}



WindsorControllerFactory:

 公共类WindsorControllerFactory:DefaultControllerFactory 
{
私人只读IWindsorContainer容器;

公共WindsorControllerFactory(IWindsorContainer容器)
{
如果(集装箱== NULL)
{
抛出新的ArgumentNullException(容器);
}
this.container =容器;
}

公共覆盖无效ReleaseController(一个IController控制器)
{
无功一次性=控制器IDisposable的;

如果(一次性!= NULL)
{
disposable.Dispose();
}

this.container.Release(控制器);
}

保护覆盖一个IController GetControllerInstance(RequestContext的RequestContext的,类型controllerType)
{
如果(controllerType == NULL)
{
返回base.GetControllerInstance(RequestContext的,controllerType);
}

无功控制器= this.container.Resolve(controllerType)作为控制器;

如果(控制器!= NULL)
{
controller.ActionInvoker = this.container.Resolve< IActionInvoker>(this.container);
}

返回控制器;
}
}




更​​新




我错过了一个细微之处:我试图用这种行为为以下内容:

 公共类CustomAuthorize:AuthorizeAttribute {...} 

这。不执行 IActionFilter



增加了以下到WindsorActionInvoker:

 保护覆盖AuthorizationContext InvokeAuthorizationFilters(controllerContext controllerContext,IList的<个IAuthorizationFilter>过滤器,actionDescriptor actionDescriptor)
{
的foreach(个IAuthorizationFilter authorizeFilter滤镜)
{
this.kernel.InjectProperties(authorizeFilter);
}
返回base.InvokeAuthorizationFilters(controllerContext,过滤器,actionDescriptor);
}



根据需要这现在工作。由于克里斯蒂亚诺,因为这是他这把我在正确的道路上慷慨地提供代码分析。


解决方案

Global.asax中

 私有静态无效bootstrapContainer()
{
容器=新WindsorContainer()
.Install( FromAssembly.This());
变种的ControllerFactory =新WindsorControllerFactory(container.Kernel);

ControllerBuilder.Current.SetControllerFactory(的ControllerFactory);
}



安装/灌装容器

 公共类ControllersInstaller:IWindsorInstaller 
{
#地区IWindsorInstaller会员

公共无效安装(IWindsorContainer容器,IConfigurationStore店)
{
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>()
。如果(Component.IsInSameNamespaceAs<&HomeController的GT;())
。如果(T => t.Name.EndsWith(控制器))
.Configure((C => c.LifeStyle.Transient)));
}

#endregion
}



WindsorControllerFactory

 使用系统; 
使用的System.Web;
使用System.Web.Mvc;
使用System.Web.Routing;

使用Castle.MicroKernel;

公共类WindsorControllerFactory:DefaultControllerFactory
{
私人只读的iKernel内核;

公共WindsorControllerFactory(内核的iKernel)
{
this.kernel =内核;
}

公共覆盖无效ReleaseController(一个IController控制器)
{
kernel.ReleaseComponent(控制器);
}

保护覆盖一个IController GetControllerInstance(RequestContext的RequestContext的,类型controllerType)
{
如果(controllerType == NULL)
{
罚球新HttpException(404的String.Format(以下简称控制器路径{0}可能不会被发现。requestContext.HttpContext.Request.Path));
}

一个IController一个IController =(一个IController)kernel.Resolve(controllerType);

//新的代码
如果(一个IController是控制器)
{
((控制器)一个IController).ActionInvoker = kernel.Resolve< IActionInvoker>();
}

返回一个IController;
}
}



WindsorActionInvoker

 命名空间WindsorExtensions.Mvc 
{

公共类WindsorActionInvoker:ControllerActionInvoker
{
只读的iKernel内核;
公共WindsorActionInvoker(内核的iKernel)
{
this.kernel =内核;
}
保护覆盖ActionExecutedContext InvokeActionMethodWithFilters(
ControllerContext controllerContext
,IList的< IActionFilter>过滤器
,ActionDescriptor actionDescriptor
,IDictionary的<字符串对象>参数)
{
的foreach(IActionFilter actionFilter滤镜)
{
kernel.InjectProperties(actionFilter);
}
返回base.InvokeActionMethodWithFilters(controllerContext,过滤器,actionDescriptor,参数);
}
}

公共静态类WindsorExtension
{
公共静态无效InjectProperties(此的iKernel内核对象目标)
{
VAR类型= target.GetType();
的foreach(在type.GetProperties(BindingFlags.Public VAR物业| BindingFlags.Instance))
{
如果(property.CanWrite&安培;&安培; kernel.HasComponent(property.PropertyType))
{
VAR值= kernel.Resolve(property.PropertyType);
尝试{property.SetValue(目标,价值,NULL); }
赶上(异常前)
{
VAR消息=的String.Format(错误设置属性{0}的类型{1},以了解更多信息,请参阅内部异常。属性。名称,type.FullName);
抛出新ComponentActivatorException(消息,前);
}
}
}
}
}
}

AgencyAuthorizeAttribute

 命名空间WpRegistration.Web.Filters 
{
[ AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,的AllowMultiple = FALSE,继承= TRUE)]
公共密封类AgencyAuthorize:ActionFilterAttribute
{
CurrentUserService _currentUserSvc;
公共AgencyAuthorize(){}

公共服务CurrentUserService
{
{返回_currentUserSvc; }

{
this._currentUserSvc =价值;
}
}


I am trying to use the approach from this article, but I am missing something - I am currently getting an error within WindsorControllerFactory.GetControllerInstance when it tries to resolve IActionInvoker since WindsorActionInvoker has a dependency on IWindsorContainer.

Given that WindsorControllerFactory already has a reference to IWindsorContainer, could I pass that reference in? If so - how? The only examples I have found are about passing value types as constructor parameters, not reference types.

I'm feeling I'm missing something obvious...

Current setup as follows: Within Global.asax Application_Start I call the following method:

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

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

        return container;
    }

ComponentRegistrar:

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

WindsorControllerFactory:

 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

I missed a subtlety: I was trying to use this behaviour for the following:

public class CustomAuthorize : AuthorizeAttribute {...}

which doesn't implement IActionFilter.

Added the following to 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);
    }

This now works as required. Thanks to Cristiano since it was analysis of his kindly provided code which put me on the right path.

解决方案

Global.asax

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

    ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}

Installer / filling container

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
}

WindsorControllerFactory

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

WindsorActionInvoker

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

AgencyAuthorizeAttribute

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

这篇关于温莎城堡 - 注射IActionInvoker执行问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆