通过AttachToComponentRegistration(激活,准备)向MVC过滤器注入Autofac MyLogger

时间:2014-12-15 12:43:03

标签: c# asp.net-mvc autofac

我试图将IMyLogger注入我的过滤器类但没有成功。这是我的代码:

属性:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class MyActionFilterAttribute : FilterAttribute, IActionFilter
{
   public IMyLogger Logger { get; set; }

   public void OnActionExecuting(ActionExecutingContext filterContext) { }
   public void OnActionExecuted(ActionExecutedContext filterContext) { }
}

注册:

var builder = new ContainerBuilder();
builder.RegisterModule<MyLoggerModule>();
builder.RegisterFilterProvider();
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>();

IContainer AutofacContainer = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(AutofacContainer));

MyLogger模块负责注入MyLogger

public class MyLoggerModule : Autofac.Module
{
   protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
   {
      registration.Preparing += (object sender, PreparingEventArgs e) => {
        var type = e.Component.Activator.LimitType;
        /* using reflection check if there is a constructor with
           parameter of type IMyLogger and if so then create logger
           and setup in constructor
         */
      };
      registration.Activated += (s, e) => {
        var type = e.Component.Activator.LimitType;
        /* using reflection check if there is a property of type
           IMyLogger and if so then create logger and setup it
         */
      }
   }
}

问题在于,当我调试PreparingActivated时,变量type永远不会设置为MyActionFilterAttribute并且因为执行Logger 1}}属性中的属性始终为null

有没有办法在过滤器中以这种方式设置记录器?

如果您想在此处尝试此操作,请准备并激活完整代码:

private bool HasConstructorDependencyOnLogger(Type type)
{
  return type.GetConstructors()
    .Any(ctor => ctor.GetParameters()
    .Any(parameter => parameter.ParameterType == typeof(IMyLogger)));
}

private IEnumerable<PropertyInfo> GetLoggerProperties(Type type)
{
  return type.GetProperties().Where(property => property.CanWrite && 
     property.PropertyType == typeof(IMyLogger) && 
     property.GetSetMethod(true).IsPublic);
}

protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
  registration.Preparing += (object sender, PreparingEventArgs e) => {
    var type = e.Component.Activator.LimitType;
    var hasDep = HasConstructorDependencyOnLogger(type);
    if (hasDep)
    {
      e.Parameters = e.Parameters.Concat(Enumerable.Repeat(
        new ResolvedParameter(
          (parameter, context) => parameter.ParameterType == typeof(ILogger), 
          (p, i) => new MyLogger(p.Member.DeclaringType)), 1));
    }
  };

  registration.Activated += (s, e) =>
  {
    var type = e.Component.Activator.LimitType;
    var properties = GetLoggerProperties(type).ToList();
    if (properties.Count > 0)
    {
      var logger = new MyLogger(type);
      foreach (var prop in properties)
      {
        prop.SetValue(e.Instance, logger, BindingFlags.SetProperty | BindingFlags.Instance, null, null, null);
      }
    }
  };
}

-------更新--------

我找到了解决此问题的方法。我已从AutofacFilterProvider继承并覆盖GetFilters方法。我在Autofac代码中找到的是:

foreach (var filter in filters)
  lifetimeScope.InjectProperties(filter.Instance);

这一行只是解析实例,并没有接受已注册的PreparingActivated来电。

我的FiltersProvider看起来像这样:

public class MyAutofacFilterProvider : AutofacFilterProvider
{
  public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
  {
     var filters = base.GetFilters(controllerContext, actionDescriptor).ToList();
     var lifetimeScope = AutofacDependencyResolver.Current.RequestLifetimeScope;

     if (lifetimeScope != null)
     {
       foreach (var filter in filters)
       {
         var actualProps = filter.Instance
                       .GetType()
                       .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                       .Where(pi => pi.CanWrite && pi.PropertyType == typeof(IMyLogger))
                       .ToList();

         foreach (var actual in actualProps)
         {
           var setter = actual.GetSetMethod();
           if (setter != null)
           {
             setter.Invoke(filter.Instance, new[] { new MyLogger(filter.Instance.GetType()) });
             break;
           }
         }
       }
     }
  }
}

此解决方案看起来很好,但每次都没有设置文件管理器中的记录器。我可以看到foreach通过set属性但后来在过滤器中为null。

这个解决方案的一个解决方案是在过滤器static中设置Logger属性,但这不是一个完美的解决方案。你知道为什么每次都没有设置Logger吗?

1 个答案:

答案 0 :(得分:0)

尝试使 MyActionFilterAttribute 实施 IAutofacActionFilter , 并把 builder.RegisterType()。AsWebApiExceptionFilterFor()。PropertiesAutowired() 进入你的autofact配置文件。

但MyActionFilterAttribute不再是属性