【问题标题】:Custom ActionFilterAttribute in .Net Core 3.1 returning: Unable to resolve service for type 'System.String'.Net Core 3.1 中的自定义 ActionFilterAttribute 返回:无法解析“System.String”类型的服务
【发布时间】:2020-06-19 10:28:44
【问题描述】:

我正在将我的 .Net Core 2.2 应用程序迁移到 3.1 版。

我有以下动作过滤器:

public class MyFilterAttribute : ActionFilterAttribute
{
    private readonly string _name;
    private readonly int _num;
    private readonly string _type;

    public MyFilterAttribute(string name, int num, string type)
    {
        _name = name;
        _num = num;
        _type = type;
    }

    public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        ...
        await base.OnActionExecutionAsync(context, next);
    }
}

我在 Startup.cs 文件中注册这个过滤器,如下所示:

services.AddTransient<MyFilterAttribute>();

我在控制器中使用过滤器,如下所示:

public class MyController : Controller
{
    [MyFilter("some-name", 5000, "some-type")]
    public async Task MyAction()
    {
        ...
    }
}

这个过滤器在我的 .Net Core 2.2 应用程序中运行良好。但是,现在当我尝试迁移到 3.1 版时,出现以下异常:

发生异常:CLR/System.AggregateException 未处理 “System.AggregateException”类型的异常发生在 Microsoft.Extensions.DependencyInjection.dll:'有些服务不是 能够构造'发现内部异常,见 $exception in 变量窗口以获取更多详细信息。最里面的异常
System.InvalidOperationException:无法解析服务类型 尝试激活时出现“System.String” 'my_app.Filters.MyFilterAttribute'。在 Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(类型 serviceType, 类型 implementationType, CallSiteChain callSiteChain, ParameterInfo[] 参数,布尔 throwIfCallSiteNotFound) 在 Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache 生命周期,类型 serviceType,类型 implementationType,CallSiteChain callSiteChain) 在 Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor 描述符,类型 serviceType,CallSiteChain callSiteChain,Int32 插槽) 在 Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain) 在 Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.ValidateService(ServiceDescriptor 描述符)

我尝试像这样全局添加过滤器:

services.AddControllersWithViews(config =>
{
    config.Filters.Add<MyFilterAttribute>();
})

但我遇到了同样的错误。

.Net Core 在 .Net Core 3.1 中读取自定义过滤器的方式是否发生了变化?

我在迁移重大更改文档中没有看到任何相关内容。

【问题讨论】:

  • 我很难相信在以前的版本中添加到服务集合时会起作用。 public MyFilterAttribute(string name, int num, string type)容器不知道如何解析这些参数
  • @Nkosi 我明白你在说什么,但我有一个正在生产的.net core 2.2 应用程序使用这个精确的过滤器......

标签: c# .net-core .net-core-3.1 actionfilterattribute custom-action-filter


【解决方案1】:

据此 (https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-3.1),您的所有操作过滤器都由 DI 解析,这意味着您的 2 个字符串参数也将被解析。这导致了你的错误。

您可能需要考虑使用不需要 DI 解决的不同类型的过滤器。

查看 2 种类型的过滤器

public class AddHeaderAttribute : ResultFilterAttribute
public class MyActionFilterAttribute : ActionFilterAttribute

【讨论】:

【解决方案2】:

Alex 和 Nkosi 的答案 (/cmets) 是正确的,第一个实现的问题是过滤器是在依赖注入机制中构建的,而 DI 不知道如何处理字符串参数。

老实说,我不知道这是如何工作的,但我确实有一个正在生产中的 .Net Core 2.2 应用程序,并以这种方式实现了过滤器。

无论如何,我将过滤器更改为 TypeFilterAttribute,现在它在 .Net Core 3.1 中再次工作(无需在 DI 中注册):

public class MyFilterAttribute : TypeFilterAttribute
{
    public MyFilterAttribute(params object[] arguments) : base(typeof(MyFilterAttributeImpl))
    {
        Arguments = new object[] { arguments };
    }

    private class MyFilterAttributeImpl : ActionFilterAttribute
    {
        private readonly string _name;
        private readonly int _num;
        private readonly string _type;

        public MyFilterAttribute(object[] arguments)
        {
            _name = (string)arguments[0];
            _num = (int)arguments[1];
            _type = (string)arguments[2];
        }

        public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            ...
            await base.OnActionExecutionAsync(context, next);
        }
    }
}

在这个实现中,我们首先定义了一个TypeFilterAttribute,并在其中调用了一个ActionFilterAttribute,我们可以用一个漂亮的注解来调用过滤器:

[MyFilter("some-name", 5000, "some-type")]

代替:

[TypeFilter(typeof(MyFilterAttribute), Arguments = new object[] { "some-name", 5000, "some-type" })]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-26
    • 1970-01-01
    • 1970-01-01
    • 2019-08-24
    • 2020-05-10
    • 2020-10-28
    • 2020-01-29
    相关资源
    最近更新 更多