如何只为一个Razor Page设置`ValidationVisitor.MaxValidationDepth`=1?

How can I set `ValidationVisitor.MaxValidationDepth` = 1 only for one Razor Page?(如何只为一个Razor Page设置`ValidationVisitor.MaxValidationDepth`=1?)
本文介绍了如何只为一个Razor Page设置`ValidationVisitor.MaxValidationDepth`=1?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在本地更改一个Razor页的ValidationVisitor.MaxValidationDepth以阻止验证子对象?

我不想像文档:Maximum recursion

那样使用MvcOptions.MaxValidationDepth全局更改它

这是一个后续问题。请检查我的原始问题以查看此处的对象结构:​

Razor Page validation error with a complex object, TryValidateModel() does not work

推荐答案

我们可以从IObjectModelValidator开始。默认实现是内部实现(DefaultObjectValidator),继承自ObjectModelValidator。基类(和抽象类)要求派生类只实现一个名为GetValidationVisitor的方法。这是您需要在ValidationVisitor运行之前修改MaxValidationDepth的一个扩展点。默认实现DefaultObjectValidator只是将MaxValidationDepth设置为从MvcOptions获得的值。因此,正如您所说,它在全球范围内应用。

IObjectModelValidator的自定义实现中(当然我们让它继承自ObjectModelValidator),您可以改为从当前上下文获取MaxValidationDepth

在执行每个页面处理程序之前,您可以设置您选择的MaxValidationDepth。要使其成为标准(像横切关注点一样使用),我们可以创建一个IAsyncPageFilter作为属性,该属性可以应用于您想要的任何页面模型类。

实现代码如下:

//the custom IObjectModelValidator (which is much like what from the source code 
//of DefaultObjectValidator)
public class ContextBasedObjectModelValidator : ObjectModelValidator
{
    readonly MvcOptions _mvcOptions;
    public ContextBasedObjectModelValidator(IModelMetadataProvider modelMetadataProvider, 
                                            IList<IModelValidatorProvider> validatorProviders,
                                            MvcOptions mvcOptions) : base(modelMetadataProvider, validatorProviders)
    {
        _mvcOptions = mvcOptions;
    }

    public override ValidationVisitor GetValidationVisitor(ActionContext actionContext, 
        IModelValidatorProvider validatorProvider, 
        ValidatorCache validatorCache, 
        IModelMetadataProvider metadataProvider, 
        ValidationStateDictionary validationState)
    {            
        var visitor = new ValidationVisitor(
            actionContext,
            validatorProvider,
            validatorCache,
            metadataProvider,
            validationState)
        {
            MaxValidationDepth = actionContext.HttpContext.Features.Get<IContextBasedMaxValidationDepthFeature>()?.MaxValidationDepth ?? _mvcOptions.MaxValidationDepth,
            ValidateComplexTypesIfChildValidationFails = _mvcOptions.ValidateComplexTypesIfChildValidationFails,
        };

        return visitor;
    }
}

//we need a class for the custom request feature to hold your context-based MaxValidationDepth
public interface IContextBasedMaxValidationDepthFeature
{
    int MaxValidationDepth { get; }
}
public class ContextBasedMaxValidationDepthFeature : IContextBasedMaxValidationDepthFeature
{
    public ContextBasedMaxValidationDepthFeature(int maxValidationDepth)
    {
        MaxValidationDepth = maxValidationDepth;
    }
    public int MaxValidationDepth { get; }
}

//here the page filter to help set your context-based MaxValidationDepth
[AttributeUsage(AttributeTargets.Class)]
public class MaxValidationDepthAttribute : Attribute, IAsyncPageFilter
{
    public MaxValidationDepthAttribute(int maxValidationDepth)
    {
        MaxValidationDepth = maxValidationDepth;
    }
    public int MaxValidationDepth { get; }
    public Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
    {
        //set the max validation depth from the predefined value (via the attribute)
        context.HttpContext.Features
               .Set<IContextBasedMaxValidationDepthFeature>(new ContextBasedMaxValidationDepthFeature(MaxValidationDepth));
        return next();
    }

    public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
    {
        return Task.CompletedTask;
    }
}

最后,我们需要在Startup.ConfigureServices中注册您的自定义IObjectModelValidator

services.Replace(new ServiceDescriptor(typeof(IObjectModelValidator), sp => {
            var options = sp.GetRequiredService<IOptions<MvcOptions>>().Value;
            var metadataProvider = sp.GetRequiredService<IModelMetadataProvider>();
            return new ContextBasedObjectModelValidator(metadataProvider, options.ModelValidatorProviders, options);
        }, ServiceLifetime.Singleton));

使用它:

//suppose you want it to be 1
//for this specific page
[MaxValidationDepth(1)]
public class YourPageModel : PageModel {
     //...
}

这篇关于如何只为一个Razor Page设置`ValidationVisitor.MaxValidationDepth`=1?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)