我们可以从IObjectModelValidator
。默认实现是内部的(DefaultObjectValidator
)并继承自ObjectModelValidator
。基(和抽象)类要求派生类仅实现一种称为GetValidationVisitor
。这是您修改的一个扩展点MaxValidationDepth
of the ValidationVisitor
在它运行之前。默认实现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;
}
}
最后我们需要注册您的自定义IObjectModelValidator
在 - 的里面Startup.ConfigureServices
:
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));
Use it:
//suppose you want it to be 1
//for this specific page
[MaxValidationDepth(1)]
public class YourPageModel : PageModel {
//...
}