繁体   English   中英

在AddValidation方法asp.net核心自定义验证中访问模型数据

[英]Access model data in AddValidation method asp.net core custom validation

我正在关注以下示例: https : //docs.microsoft.com/zh-cn/aspnet/core/mvc/models/validation并尝试实现自己的自定义属性进行验证。

现在,viewmodel有两个字段,我希望从该方法内部进行访问,以便可以使用“ data-val”属性来呈现它们。 我的问题是,如何从上下文中说出一个名为“ Myprop”的属性? 当我调试时,我可以在context.ActionContext.ViewData.Model下获取信息,但是除了调试期间,当我使用Visual Studio“快速监视”功能时,我无法获得该信息。 定制属性位于视图模型上的属性上。

public void AddValidation(ClientModelValidationContext context)
{
    if (context == null)
    {
       throw new ArgumentNullException(nameof(context));
    }

    MergeAttribute(context.Attributes, "data-val", "true");
    MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage());

    var year = _year.ToString(CultureInfo.InvariantCulture);
    MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
}

我遇到了类似的问题。 简短的答案是你不能从那儿 您只能从那里访问元数据,而不能访问实际模型。 这样做的原因是您的模型元数据和基于它的验证是在首次使用时完成的,然后进行缓存。 因此,您将永远无法通过属性装饰器更改基于模型返回的验证规则。

如果您需要根据模型的实例/内容动态决定要渲染的客户端data-val-*属性,则需要从DefaultValidationHtmlAttributeProvider继承而不是使用属性,并重写AddValidationAttributes方法。 到目前为止,这是我发现这样做的唯一方法。 这是因为在此方法内部,您可以访问ModelExplorer

public class CustomValidationHtmlAttributeProvider : DefaultValidationHtmlAttributeProvider
{
    private readonly IModelMetadataProvider metadataProvider;

    public CustomValidationHtmlAttributeProvider(IOptions<MvcViewOptions> optionsAccessor, IModelMetadataProvider metadataProvider, ClientValidatorCache clientValidatorCache)
        : base(optionsAccessor, metadataProvider, clientValidatorCache)
    {
        this.metadataProvider = metadataProvider;
    }

    public override void AddValidationAttributes(ViewContext viewContext, ModelExplorer modelExplorer, IDictionary<string, string> attributes)
    {
        //base implimentation
        base.AddValidationAttributes(viewContext, modelExplorer, attributes);

        //re-create the validation context (since it's encapsulated inside of the base implimentation)
        var context = new ClientModelValidationContext(viewContext, modelExplorer.Metadata, metadataProvider, attributes);

        //Only proceed if it's the model you need to do custom logic for
        if (!(modelExplorer.Container.Model is MyViewModelClass model) || !modelExplorer.Metadata.PropertyName == "Myprop") return;

        //Do stuff!
        var validationAttributeAdapterProvider = viewContext.HttpContext.RequestServices.GetRequiredService<IValidationAttributeAdapterProvider>();

        if (model.Myprop)
        {
            var validationAdapter = (RequiredAttributeAdapter)validationAttributeAdapterProvider.GetAttributeAdapter(new RequiredAttribute(), null);
            validationAdapter.Attribute.ErrorMessage = "You not enter right stuff!";
            validationAdapter.AddValidation(context);
        }
    }
}

然后在您的StartupConfigureServices()中注册此类

public void ConfigureServices(IServiceCollection services)
{
    //All your other DI stuff here

    //register the new ValidationHtmlAttributeProvider
    services.AddSingleton<ValidationHtmlAttributeProvider, PseudoAttributeValidationHtmlAttributeProvider>();
}

不利的一面是,如果您有多个模型需要这样做,那么它很快就会变得非常丑陋。 如果有人找到了更好的方法,我很想听听:-)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM