ASP.NET Core 2.1动作过滤器因缺少合适构造函数报错
这个错误的核心问题很明确:你的ClaimRequirementFilter类没有提供匹配ClaimRequirementAttribute传递参数的公共构造函数,导致DI容器无法正确创建它的实例。下面是一步步的修复方案:
1. 给ClaimRequirementFilter添加正确的构造函数
你在ClaimRequirementAttribute里已经通过Arguments传递了一个Claim对象,但你的过滤器类根本没有对应的构造函数来接收这个参数。另外,我建议把IAccountLogic通过构造注入的方式传入,而不是在OnAuthorization方法里手动从服务容器获取——这样代码更优雅,也更符合依赖注入的最佳实践。修改后的过滤器代码如下:
public class ClaimRequirementFilter : IAuthorizationFilter { private readonly Claim _requiredClaim; private readonly IAccountLogic _accountLogic; // 构造函数接收从Attribute传过来的Claim,以及DI注入的IAccountLogic public ClaimRequirementFilter(Claim requiredClaim, IAccountLogic accountLogic) { _requiredClaim = requiredClaim; _accountLogic = accountLogic; } public void OnAuthorization(AuthorizationFilterContext context) { var headers = context.HttpContext.Request.Headers; var tokenSuccess = headers.TryGetValue("Token", out var token); var emailSuccess = headers.TryGetValue("Email", out var email); var deviceNameSuccess = headers.TryGetValue("DeviceName", out var deviceName); if (tokenSuccess && emailSuccess && deviceNameSuccess) { // 直接用构造注入的_accountLogic,不用再手动从容器获取 var hasClaim = _accountLogic.ValidateLogin(email, token, deviceName).Result.Success; if (!hasClaim) { context.HttpContext.ForbidAsync(); } } else { context.HttpContext.ForbidAsync(); } } }
2. 修正Startup中的服务注册
因为你用的是TypeFilterAttribute,它会自动处理过滤器的实例化:既会从DI容器中解析依赖(比如IAccountLogic),也会结合你传入的Arguments创建实例。所以你不需要手动把ClaimRequirementFilter注册到DI容器里,请移除Startup中这一行:
services.AddScoped<ClaimRequirementFilter>();
另外要确保你的IAccountLogic已经正确注册到DI容器(比如通过services.AddScoped<IAccountLogic, AccountLogic>()),这样过滤器才能顺利获取到它的实例。
3. 验证Attribute的参数传递
你的ClaimRequirementAttribute的构造函数已经正确传递了Claim参数,这部分不需要修改,但可以确认一下ClaimRoles枚举的ToString()输出是否符合你的预期:
public class ClaimRequirementAttribute : TypeFilterAttribute { public ClaimRequirementAttribute(string claimType, ClaimRoles claimValue) : base(typeof(ClaimRequirementFilter)) { Arguments = new object[] { new Claim(claimType, claimValue.ToString()) }; } }
错误原因复盘
当TypeFilterAttribute尝试创建ClaimRequirementFilter实例时,它会扫描过滤器的所有公共构造函数,试图找到一个能匹配你传入的Arguments(这里是一个Claim对象)加上DI能提供的服务的构造函数。之前你的过滤器只有默认的无参构造函数,但你又传递了Arguments,导致DI找不到合适的构造函数组合,最终抛出了InvalidOperationException。
内容的提问来源于stack exchange,提问作者Mech0z

