如何在AspNetCore.Identity的IdentityErrorDescriber中添加新方法并解决调用报错
一、解决编译错误(CS1061)
报错原因是UserManager.ErrorDescriber的类型是基类IdentityErrorDescriber,而你自定义的InvalidPhoneNumber方法仅存在于子类AuthErrorDescriber中,直接调用会触发编译失败。以下是两种可行的解决方式:
1. 显式转换为自定义错误描述器类型
因为你已经通过AddErrorDescriber<AuthErrorDescriber>()注册了自定义实现,ErrorDescriber的实际实例是AuthErrorDescriber,可以通过强制转换或as关键字获取子类实例:
if (string.IsNullOrEmpty(phoneNumber) || !PhoneNumberHelper.IsValid(phoneNumber)) { var authDescriber = userManager.ErrorDescriber as AuthErrorDescriber; if (authDescriber == null) { // 处理转换失败的边界情况 var defaultError = new IdentityError { Code = "InvalidPhoneNumber", Description = "Invalid phone number." }; return CreateValidationProblem(IdentityResult.Failed(defaultError)); } return CreateValidationProblem(IdentityResult.Failed(authDescriber.InvalidPhoneNumber(phoneNumber))); }
如果能确保注册的一定是AuthErrorDescriber,也可以直接强制转换:
return CreateValidationProblem(IdentityResult.Failed(((AuthErrorDescriber)userManager.ErrorDescriber).InvalidPhoneNumber(phoneNumber)));
2. 通过依赖注入直接获取自定义错误描述器
在控制器或服务的构造函数中直接注入AuthErrorDescriber,跳过从UserManager获取的步骤:
// 控制器构造函数 private readonly UserManager<User> _userManager; private readonly AuthErrorDescriber _errorDescriber; public AuthController(UserManager<User> userManager, AuthErrorDescriber errorDescriber) { _userManager = userManager; _errorDescriber = errorDescriber; } // 调用处代码 if (string.IsNullOrEmpty(phoneNumber) || !PhoneNumberHelper.IsValid(phoneNumber)) { return CreateValidationProblem(IdentityResult.Failed(_errorDescriber.InvalidPhoneNumber(phoneNumber))); }
二、其他添加新错误的方式
除了继承IdentityErrorDescriber,还有两种灵活的方式可以添加自定义错误:
1. 直接创建IdentityError实例
如果只是个别场景需要该错误,无需扩展错误描述器,直接实例化IdentityError即可:
if (string.IsNullOrEmpty(phoneNumber) || !PhoneNumberHelper.IsValid(phoneNumber)) { var error = new IdentityError { Code = "InvalidPhoneNumber", Description = $"PhoneNumber '{phoneNumber}' is invalid." }; return CreateValidationProblem(IdentityResult.Failed(error)); }
2. 给IdentityErrorDescriber写扩展方法
通过扩展方法让所有IdentityErrorDescriber实例都能调用自定义错误方法,同时兼容自定义实现:
public static class IdentityErrorDescriberExtensions { public static IdentityError InvalidPhoneNumber(this IdentityErrorDescriber describer, string? phoneNumber) { // 如果是自定义描述器实例,优先调用其方法 if (describer is AuthErrorDescriber authDescriber) { return authDescriber.InvalidPhoneNumber(phoneNumber); } // 否则返回默认错误 return new IdentityError { Code = nameof(InvalidPhoneNumber), Description = $"PhoneNumber '{phoneNumber}' is invalid." }; } }
之后就可以直接调用userManager.ErrorDescriber.InvalidPhoneNumber(phoneNumber),不会出现编译错误。
补充:解决资源文件无法使用的问题
如果想在自定义错误描述器中使用本地化资源,可以注入IStringLocalizer:
public class AuthErrorDescriber : IdentityErrorDescriber { private readonly IStringLocalizer<AuthErrorDescriber> _localizer; public AuthErrorDescriber(IStringLocalizer<AuthErrorDescriber> localizer) { _localizer = localizer; } public virtual IdentityError InvalidPhoneNumber(string? phoneNumber) { return new IdentityError { Code = nameof(InvalidPhoneNumber), Description = _localizer["PhoneNumber '{0}' is invalid.", phoneNumber] }; } }
只需提前创建对应的资源文件(如AuthErrorDescriber.resx),即可实现错误信息的本地化。
内容的提问来源于stack exchange,提问作者bcExpt1123

