在 ASP.NET 中为现有电子邮件创建自定义验证

在 ASP.NET 中为现有电子邮件创建自定义验证
在 ASP.NET 中为现有电子邮件创建自定义验证

了解自定义验证器和依赖注入

ASP.NET 提供了用于开发健壮 Web 应用程序的强大工具,包括创建自定义验证属性的能力,以帮助确保数据完整性和用户合规性。对于初学者来说,添加此类验证(尤其是依赖项注入)的概念似乎令人畏惧。在这种情况下,我们的目标是开发一个自定义验证属性,利用应用程序中已定义的服务来验证系统中是否已存在电子邮件地址。

该过程涉及通过自定义验证属性的构造函数集成 IUserService,然后使用该服务来检查数据库中电子邮件是否存在。这种方法突出了 ASP.NET 验证框架与其对依赖项注入的支持的结合,从而使代码更加简洁、更易于维护。然而,在验证属性中集成依赖注入带来了独特的挑战,特别是与属性配置和服务生命周期相关的挑战。

命令 描述
ActivatorUtilities.CreateInstance 用于创建类型的实例,利用服务提供者来获取必要的依赖项。
HttpContextAccessor().HttpContext.RequestServices 提供对 HTTP 上下文的服务集合的访问,对于在非控制器上下文中动态检索服务很有用。
AddControllersWithViews 将 MVC 服务注册到容器,使控制器和视图能够在应用程序中使用,并具有附加选项配置。
BuildServiceProvider 从服务集合构建服务提供者,允许创建了解所有注册服务的服务范围。
ModelMetadataDetailsProviders 添加元数据详细信息提供程序,可用于在应用程序启动时添加或修改模型元数据。
InlineValidatorProvider 自定义验证器提供程序,支持集成依赖于通过依赖项注入解析的服务的验证逻辑。

解释 ASP.NET 中的依赖注入的自定义验证

提供的示例演示了如何在 ASP.NET Core 应用程序中将自定义验证属性与依赖项注入集成,这是确保服务等依赖项可以注入到验证逻辑中的关键功能,从而实现更动态、更健壮的数据验证策略。此设置中的关键组件是 ActivatorUtilities.CreateInstance 方法。当您需要在属性内创建类型(例如服务)的实例(本机不支持构造函数注入)时,此方法特别有用。它的工作原理是使用以下命令从 ASP.NET Core 的依赖注入容器手动获取服务: HttpContextAccessor().HttpContext.RequestServices

此服务检索是在自定义属性的构造函数中执行的,允许该属性使用以下服务: IUserService 执行运行时数据检查,例如验证数据库中是否已存在电子邮件。此外,使用 AddControllersWithViews 并使用选项配置它 ModelMetadataDetailsProviders 允许增强对模型及其验证处理方式的控制。此配置对于将自定义验证逻辑注入 MVC 管道至关重要,从而与 ASP.NET Core 的验证框架无缝集成。该方法演示了 ASP.NET Core 的可扩展和模块化框架的复杂使用,以解决现代 Web 应用程序中常见的复杂验证场景。

在 ASP.NET 的自定义验证属性中实现依赖注入

C# ASP.NET Core 实现

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class EmailAlreadyExistsAttribute : ValidationAttribute
{
    private readonly IUserService _userService;
    public EmailAlreadyExistsAttribute() : base(() => ActivatorUtilities.CreateInstance<IUserService>(new HttpContextAccessor().HttpContext.RequestServices))
    {
        _userService = (IUserService)HttpContextAccessor().HttpContext.RequestServices.GetService(typeof(IUserService));
    }
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        string email = value as string;
        if (_userService.CheckIfUserWithTheEmailAlreadyExists(email))
        {
            return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
        }
        return ValidationResult.Success;
    }
}

增强 API 控制器以支持 ASP.NET 中的依赖项注入属性

C# ASP.NET Core 依赖注入配置

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IUserService, UserService>();
    services.AddControllersWithViews(options =>
    {
        options.ModelMetadataDetailsProviders.Add(new ValidationProvider<IUserService>(services.BuildServiceProvider().GetService<IUserService>()));
    });
}
public class ValidationProvider<T> : IMetadataDetailsProvider where T : notnull
{
    private readonly T _service;
    public ValidationProvider(T service)
    {
        _service = service;
    }
    public void CreateValidationMetadata(ValidationMetadataProviderContext context)
    {
        context.ValidationMetadata.ValidatorProviders.Add(new InlineValidatorProvider(_service));
    }
}

ASP.NET 验证属性中的高级依赖注入技术

在 ASP.NET 中的自定义验证属性中实现依赖项注入的一个关键方面涉及了解服务生命周期和范围。属性内的依赖注入并不简单,因为属性是在编译时应用的元数据,因此无法直接接受运行时数据(如 DI 容器提供的服务)。这使得利用访问 HTTP 上下文或使用服务定位器间接注入依赖项等技术变得至关重要。此类方法有助于维护干净且可测试的代码,同时遵循 ASP.NET Core 的依赖管理最佳实践。

此外,了解如何解决不支持直接服务注入的属性构造函数的限制需要更深入地了解 ASP.NET Core 的内部结构。开发人员必须确保在属性内访问的服务是线程安全的并且范围正确,以避免运行时出现任何潜在问题。这种高级理解有助于在 ASP.NET Core 应用程序中创建更强大且可维护的验证机制,从而提高应用程序的可靠性和开发人员的工作效率。

ASP.NET 自定义验证常见问题解答

  1. 的作用是什么 IUserService 在自定义验证属性中?
  2. IUserService 通常用于与用户数据交互。在自定义验证属性中,它用于检查数据库中是否已存在具有特定电子邮件的用户。
  3. 可以直接在属性构造函数中使用依赖注入吗?
  4. 不,属性构造函数不直接支持依赖注入,因为它们是元数据,并且在编译时而不是运行时进行评估。
  5. 如何将服务注入到 ASP.NET Core 中的属性中?
  6. 可以使用以下方式注入服务 ActivatorUtilities 通过访问全局服务提供者在属性内动态创建服务实例。
  7. 在验证属性中使用单例服务是否安全?
  8. 是的,但前提是服务不维护状态。单例服务必须是线程安全的,才能在可由多个线程同时访问的属性中安全使用。
  9. 处理自定义验证属性中的依赖关系的最佳实践是什么?
  10. 最佳实践是使用间接服务解析方法,例如通过 HttpContext 或使用 ActivatorUtilities。这保持了关注点分离,并确保属性与特定实现保持分离。

关于依赖注入和自定义验证器的见解

在 ASP.NET 中的自定义验证属性中使用依赖项注入的探索揭示了现代软件开发框架的强大功能和复杂性。成功实现这些功能不仅可以增强应用程序的稳健性和可靠性,还可以加深开发人员对 ASP.NET 功能和体系结构细微差别的理解。通过提供的示例和讨论,开发人员可以更有信心地浏览这些高级主题,确保他们的应用程序能够以可扩展和可维护的方式有效管理用户输入验证。