Skip to main content
 首页 » 编程设计

c#之将属性注入(inject) web api 过滤器 Autofac

2024年02月05日25落叶无声

我有一个小过滤器

public class Action1DebugActionWebApiFilter : ActionFilterAttribute 
{ 
    public IMyclass myClass { get; set; } 
 
    public override void OnActionExecuting(HttpActionContext actionContext) 
    { 
        // pre-processing 
        Debug.WriteLine("ACTION 1 DEBUG pre-processing logging"); 
    } 
 
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) 
    { 
        var objectContent = actionExecutedContext.Response.Content as ObjectContent; 
        if (objectContent != null) 
        { 
            var type = objectContent.ObjectType; //type of the returned object 
            var value = objectContent.Value; //holding the returned value 
        } 
 
        Debug.WriteLine("ACTION 1 DEBUG  OnActionExecuted Response " + actionExecutedContext.Response.StatusCode.ToString()); 
    } 
} 

我希望 IMyclass 注入(inject)一个从 AutoFac 解析的类。

builder.RegisterType<IMyclass >().As<MyClass>().InstancePerRequest(); 

然而它仍然是null。我的所有其他注入(inject)在构造函数中都工作正常,但在属性中却没有。

请您参考如下方法:

属性根本不是 DI 友好的。它们由 .NET 框架实例化,因此您无法控制它们具有的依赖项。所以,最好的解决办法就是放弃使用ActionFilterAttribute的想法。完全。

正如 passive attributes 中指出的那样, 你可以分解你的 ActionFilterAttribute进入它的 2 个继承特性:

  1. 安 Attribute子类(不包含任何行为)。
  2. DI 友好 IActionFilter 子类(使用构造函数注入(inject))。

Action1DebugAttribute

首先,有一个属性来标记您的 Controller 和操作。此属性根本不包含任何行为(但如果需要,它可能包含类似 this example 的属性)。

// This attribute should contain no behavior. No behavior, nothing needs to be injected. 
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)] 
public class Action1DebugAttribute : Attribute 
{} 

Action1DebugActionWebApiFilter

这是 DI 友好的 Action 过滤器。如果需要,我们可以使用构造函数注入(inject)或属性注入(inject)。为了简单起见,此示例使用构造函数注入(inject)。

public class Action1DebugActionWebApiFilter : IActionFilter 
{ 
    private readonly IMyclass myClass; 
 
    public Action1DebugActionWebApiFilter(IMyClass myClass) 
    { 
        if (myClass == null) 
            throw new ArgumentNullException("myClass"); 
        this.myClass = myClass; 
    } 
 
    public override void OnActionExecuting(HttpActionContext actionContext) 
    { 
        if (this.IsFilterDefined(actionContext.ActionDescriptor)) 
        { 
            // pre-processing 
            Debug.WriteLine("ACTION 1 DEBUG pre-processing logging"); 
        } 
    } 
 
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) 
    { 
        if (this.IsFilterDefined(actionExecutedContext.ActionDescriptor)) 
        { 
            var objectContent = actionExecutedContext.Response.Content as ObjectContent; 
            if (objectContent != null) 
            { 
                var type = objectContent.ObjectType; //type of the returned object 
                var value = objectContent.Value; //holding the returned value 
            } 
 
            Debug.WriteLine("ACTION 1 DEBUG  OnActionExecuted Response " + actionExecutedContext.Response.StatusCode.ToString()); 
        } 
    } 
 
    private bool IsFilterDefined(ActionDescriptor actionDescriptor) 
    { 
        return actionDescriptor.IsDefined(typeof(Action1DebugAttribute), inherit: true) 
            || actionDescriptor.ControllerDescriptor.IsDefined(typeof(Action1DebugAttribute), inherit: true); 
    } 
} 

用法

完成此操作后,您可以简单地使用 Autofac 来解析您的操作过滤器及其在组合根中的所有依赖项。

注册

builder.RegisterType<IMyclass>().As<MyClass>(); 
// Since it is possible more than one `IActionFilter` is registered, 
// we are using a named type. You could alternatively create another  
// interface to uniquely identify this action filter. 
builder.RegisterType<IActionFilter>() 
       .Named<Action1DebugActionWebApiFilter>("action1DebugActionWebApiFilter"); 

正在解决

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters, IContainer container) 
    { 
        filters.Add(container.ResolveNamed<IActionFilter>("action1DebugActionWebApiFilter")); 
        filters.Add(new HandleErrorAttribute()); 
    } 
} 

生命周期

您将无法在每个请求生命周期内使用实例,因为操作过滤器是作为 MVC 对象图的一部分创建的,而不是根据请求解析。

但是,您这样做的愿望表明 IMyClass实例中有一些适用于当前请求的状态。如果不是这种情况,那么您可以按原样使用此代码。

另一方面,如果您的对象是有状态的,那么您可以使用以下方法之一在运行时解析它:

  1. 注入(inject) Abstract Factory创建你的 MyClass实例而不是将类直接注入(inject)过滤器。
  2. 注入(inject) Func<Type, IMyClass>进入过滤器以调用组合根内部的匿名方法,该方法使用容器来解析实例 as shown here .