【发布时间】: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
*/
}
}
}
问题是,当我调试Preparing 和Activated 时,变量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);
此行仅解析实例,不接受注册的Preparing 或Activated 调用。
我的 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