From ef15da3f6e120ec259a990e1d88de6fd4013163e Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 19 Sep 2022 11:03:16 +0200 Subject: [PATCH] Bypass model validation for rendering models (#12999) undefined --- .../Extensions/TypeExtensions.cs | 10 ++++++++ .../Mvc/UmbracoMvcConfigureOptions.cs | 3 +++ ...enderingModelValidationMetadataProvider.cs | 18 +++++++++++++ .../BypassRenderingModelValidatorProvider.cs | 25 +++++++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 src/Umbraco.Web.Common/Extensions/TypeExtensions.cs create mode 100644 src/Umbraco.Web.Common/Validators/BypassRenderingModelValidationMetadataProvider.cs create mode 100644 src/Umbraco.Web.Common/Validators/BypassRenderingModelValidatorProvider.cs diff --git a/src/Umbraco.Web.Common/Extensions/TypeExtensions.cs b/src/Umbraco.Web.Common/Extensions/TypeExtensions.cs new file mode 100644 index 0000000000..60edea5b15 --- /dev/null +++ b/src/Umbraco.Web.Common/Extensions/TypeExtensions.cs @@ -0,0 +1,10 @@ +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; + +namespace Umbraco.Extensions; + +internal static class TypeExtensions +{ + public static bool IsRenderingModel(this Type type) + => typeof(ContentModel).IsAssignableFrom(type) || typeof(IPublishedContent).IsAssignableFrom(type); +} diff --git a/src/Umbraco.Web.Common/Mvc/UmbracoMvcConfigureOptions.cs b/src/Umbraco.Web.Common/Mvc/UmbracoMvcConfigureOptions.cs index 246e313b9a..eb4991fec3 100644 --- a/src/Umbraco.Web.Common/Mvc/UmbracoMvcConfigureOptions.cs +++ b/src/Umbraco.Web.Common/Mvc/UmbracoMvcConfigureOptions.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Umbraco.Cms.Web.Common.Filters; using Umbraco.Cms.Web.Common.ModelBinders; +using Umbraco.Cms.Web.Common.Validators; namespace Umbraco.Cms.Web.Common.Mvc; @@ -18,6 +19,8 @@ public class UmbracoMvcConfigureOptions : IConfigureOptions public void Configure(MvcOptions options) { options.ModelBinderProviders.Insert(0, new ContentModelBinderProvider()); + options.ModelValidatorProviders.Insert(0, new BypassRenderingModelValidatorProvider()); + options.ModelMetadataDetailsProviders.Add(new BypassRenderingModelValidationMetadataProvider()); options.Filters.Insert(0, new EnsurePartialViewMacroViewContextFilterAttribute()); } } diff --git a/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidationMetadataProvider.cs b/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidationMetadataProvider.cs new file mode 100644 index 0000000000..94f0dea502 --- /dev/null +++ b/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidationMetadataProvider.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Web.Common.Validators; + +/// +/// Ensures we bypass object graph validation for rendering models. +/// +internal class BypassRenderingModelValidationMetadataProvider : IValidationMetadataProvider +{ + public void CreateValidationMetadata(ValidationMetadataProviderContext context) + { + if (context.Key.ModelType.IsRenderingModel()) + { + context.ValidationMetadata.ValidateChildren = false; + } + } +} diff --git a/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidatorProvider.cs b/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidatorProvider.cs new file mode 100644 index 0000000000..ab52483180 --- /dev/null +++ b/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidatorProvider.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Web.Common.Validators; + +/// +/// Ensures we bypass property validation for rendering models. +/// +internal class BypassRenderingModelValidatorProvider : IModelValidatorProvider +{ + public void CreateValidators(ModelValidatorProviderContext context) + { + if (context.ModelMetadata.ModelType.IsRenderingModel()) + { + context.Results.Clear(); + context.Results.Add(new ValidatorItem + { + Validator = null, + IsReusable = true + }); + } + } +} + +