验证Attribute注入服务,以实现不引人注目的客户验证



我有一个相对简单的验证attribute,它需要一些服务才能完成ISVALID方法 - 基本上只是检索ID列表以将所选值与之相比。正如本文所建议的那样,我正在使用服务定位器模式在服务器端获取这些图案,这很好。

但是,我也想在客户端上执行相同的验证,但是请尝试,因为我可能找不到通过属性添加相同数据的方法,或者就此而言,将其设置在属性本身上足够早 - 使得属性可以掌握它 - 这样我就可以将ID添加到MergeAttribute调用中,从而在客户端端使用一些JavaScript访问它们。

这甚至可能吗?任何想法都是最有用的

上下文的简化代码...

验证:

public class InvalidIdAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var configService = validationContext.GetService<IProductService>();
        var productIds = configService.GetIds()
        var selectedId = (int)value;
        var invalidId = productIds.SingleOrDefault(p => p.Invalid && p.Id == selectedId);
        if (invalidId != null)
            return new ValidationResult(FormatErrorMessage(invalidId.Name));
        return ValidationResult.Success;
    }
}

和attributeadapter

public class InvalidIdAttributeAdapter : AttributeAdapterBase<InvalidIdAttribute>
{
    private readonly InvalidIdAttribute _attribute;
    public InvalidIdAttributeAdapter(InvalidIdAttribute attribute, IStringLocalizer stringLocalizer)
        : base(attribute, stringLocalizer)
    {
        _attribute = attribute;
    }
    public override void AddValidation(ClientModelValidationContext context)
    {
        //how do I get the productService in here?
        var invalidIds = productService.GetIds().Where(p=>p.Invalid==true).Select(p=>p.Id);
        var pipedIds = string.Join("|", invalidIds);
        MergeAttribute(context.Attributes, "data-val", "true");
        MergeAttribute(context.Attributes, "data-val-invalidid", GetErrorMessage(context));
        MergeAttribute(context.Attributes, "data-val-invalidid-props", pipedIds); 
    }
    public override string GetErrorMessage(ModelValidationContextBase validationContext)
    {
        return _attribute.FormatErrorMessage(validationContext.ModelMetadata.GetDisplayName());
    }
}

适当的方法是仅依靠该服务作为属性适配器的一部分。因此,只需在其构造函数中添加其他依赖项:

public class InvalidIdAttributeAdapter : AttributeAdapterBase<InvalidIdAttribute>
{
    private readonly InvalidIdAttribute _attribute;
    private readonly IProductService _productService;
    public InvalidIdAttributeAdapter(InvalidIdAttribute attribute, IStringLocalizer stringLocalizer, IProductService _productService)
        : base(attribute, stringLocalizer)
    {
        _attribute = attribute;
        _productService = productService;
    }
    public override void AddValidation(ClientModelValidationContext context)
    {
        var invalidIds = _productService.GetIds()…;
        // …
    }
}

如果要通过自定义属性适配器提供程序构造属性适配器,则必须将其依赖于服务,然后将其传递给属性适配器。由于属性适配器提供程序已注册并通过依赖项注入容器解决,因此您只需在其构造函数中添加其他依赖项。

请注意,如果您的IProductService取决于范围的依赖关系,例如数据库上下文,然后您必须将属性适配器提供商注册为范围的依赖关系本身,而不是单身人士:

services.AddScoped<IValidationAttributeAdapterProvider, InvalidIdAttributeAdapterProvider>();

最新更新