【问题标题】:Autofac MyLogger injection to MVC filters through AttachToComponentRegistration (Activated, Preparing)Autofac MyLogger 通过 AttachToComponentRegistration 向 MVC 过滤器注入(已激活,准备中)
【发布时间】:2015-03-06 12:52:53
【问题描述】:

我正在尝试将 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 属性始终是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 吗?

【问题讨论】:

    标签: c# asp.net-mvc autofac


    【解决方案1】:

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

    然而 MyActionFilterAttribute 不再是一个属性

    【讨论】:

      猜你喜欢
      • 2017-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-13
      • 1970-01-01
      • 2015-07-15
      • 1970-01-01
      相关资源
      最近更新 更多