Castle Windsor – 注入IActionInvoker实施问题

我正在尝试使用本文中的方法,但我遗漏了一些东西 – 我当前在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; } 

ComponentRegistrar:

  public static void AddComponentsTo(IWindsorContainer container) { //add other components..... container.AddComponentLifeStyle(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 filters, ActionDescriptor actionDescriptor, IDictionary 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(this.container); } return controller; } } 

更新

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

 public class CustomAuthorize : AuthorizeAttribute {...} 

它没有实现IActionFilter

在WindsorActionInvoker中添加了以下内容:

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

现在可以根据需要使用。 感谢克里斯蒂亚诺,因为它分析了他提供的善意代码,这使我走上了正确的道路。

Global.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().LifeStyle.Transient); container.Register(Component.For().ImplementedBy().LifeStyle.Transient); container.Register(AllTypes.FromThisAssembly() .BasedOn() .If(Component.IsInSameNamespaceAs()) .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(); } 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 filters , ActionDescriptor actionDescriptor , IDictionary 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; } }