.Net Core 3.1 中的自定义 ActionFilterAttribute 返回:无法解析类型 'System.String' 的服务
Custom ActionFilterAttribute in .Net Core 3.1 returning: Unable to resolve service for type 'System.String'
我正在将我的 .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 版时,出现以下异常:
Exception has occurred: CLR/System.AggregateException An unhandled
exception of type 'System.AggregateException' occurred in
Microsoft.Extensions.DependencyInjection.dll: 'Some services are not
able to be constructed' Inner exceptions found, see $exception in
variables window for more details. Innermost exception
System.InvalidOperationException : Unable to resolve service for type
'System.String' while attempting to activate
'my_app.Filters.MyFilterAttribute'. at
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type
serviceType, Type implementationType, CallSiteChain callSiteChain,
ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache
lifetime, Type serviceType, Type implementationType, CallSiteChain
callSiteChain) at
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor
descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
at
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor
serviceDescriptor, CallSiteChain callSiteChain) at
Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.ValidateService(ServiceDescriptor
descriptor)
我试过像这样全局添加过滤器:
services.AddControllersWithViews(config =>
{
config.Filters.Add<MyFilterAttribute>();
})
但我遇到了同样的错误。
.Net Core 在 .Net Core 3.1 中读取自定义过滤器的方式有什么变化吗?
我在迁移重大更改文档中没有看到任何相关内容。
根据这个 (https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-3.1),您所有的操作过滤器都由 DI 解析,这意味着您的 2 个字符串参数也将被解析。这导致了你的错误。
您可能需要考虑使用不需要由 DI 解析的不同类型的过滤器。
在
查看两种过滤器
public class AddHeaderAttribute : ResultFilterAttribute
public class MyActionFilterAttribute : ActionFilterAttribute
Alex 和 Nkosi 的回答(/评论)是正确的,第一个实现的问题是过滤器是在依赖注入机制中构建的,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" })]
我正在将我的 .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 版时,出现以下异常:
Exception has occurred: CLR/System.AggregateException An unhandled exception of type 'System.AggregateException' occurred in Microsoft.Extensions.DependencyInjection.dll: 'Some services are not able to be constructed' Inner exceptions found, see $exception in variables window for more details. Innermost exception
System.InvalidOperationException : Unable to resolve service for type 'System.String' while attempting to activate 'my_app.Filters.MyFilterAttribute'. at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.ValidateService(ServiceDescriptor descriptor)
我试过像这样全局添加过滤器:
services.AddControllersWithViews(config =>
{
config.Filters.Add<MyFilterAttribute>();
})
但我遇到了同样的错误。
.Net Core 在 .Net Core 3.1 中读取自定义过滤器的方式有什么变化吗?
我在迁移重大更改文档中没有看到任何相关内容。
根据这个 (https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-3.1),您所有的操作过滤器都由 DI 解析,这意味着您的 2 个字符串参数也将被解析。这导致了你的错误。
您可能需要考虑使用不需要由 DI 解析的不同类型的过滤器。
在
查看两种过滤器public class AddHeaderAttribute : ResultFilterAttribute
public class MyActionFilterAttribute : ActionFilterAttribute
Alex 和 Nkosi 的回答(/评论)是正确的,第一个实现的问题是过滤器是在依赖注入机制中构建的,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" })]