Skip to content

Commit

Permalink
Merge pull request #1773 from riganti/fix-config-ClientSideValidation
Browse files Browse the repository at this point in the history
Fix config.ClientSideValidation switch, remove redundant vm.validationRules property
  • Loading branch information
tomasherceg committed Feb 21, 2024
2 parents 05f679c + 8d32756 commit 5f8a459
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace DotVVM.Framework.Runtime
public static class HotReloadMetadataUpdateHandler
{
internal static readonly ConcurrentBag<WeakReference<ViewModelSerializationMapper>> SerializationMappers = new();
internal static readonly ConcurrentBag<WeakReference<ViewModelTypeMetadataSerializer>> TypeMetadataSerializer = new();
internal static readonly ConcurrentBag<WeakReference<UserColumnMappingCache>> UserColumnMappingCaches = new();
internal static readonly ConcurrentBag<WeakReference<ExtensionMethodsCache>> ExtensionMethodsCaches = new();
public static void ClearCache(Type[]? updatedTypes)
Expand All @@ -36,6 +37,11 @@ public static void ClearCache(Type[]? updatedTypes)
problematicTypes.Add(u);
}
}
foreach (var tRef in TypeMetadataSerializer)
{
if (tRef.TryGetTarget(out var t))
t.ClearCaches(updatedTypes);
}
foreach (var cRef in UserColumnMappingCaches)
{
if (cRef.TryGetTarget(out var c))
Expand All @@ -47,7 +53,6 @@ public static void ClearCache(Type[]? updatedTypes)
e.ClearCaches(updatedTypes);
}

ViewModelTypeMetadataSerializer.ClearCaches(updatedTypes);
DefaultViewModelLoader.ClearCaches(updatedTypes);
AttributeViewModelParameterBinder.ClearCaches(updatedTypes);
ChildViewModelsCache.ClearCaches(updatedTypes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,6 @@ public void BuildViewModel(IDotvvmRequestContext context, object? commandResult)
if (viewModelConverter.EncryptedValues.Count > 0)
viewModelToken["$encryptedValues"] = viewModelProtector.Protect(viewModelConverter.EncryptedValues.ToString(Formatting.None), context);

// serialize validation rules
bool useClientSideValidation = context.Configuration.ClientSideValidation;
var validationRules = useClientSideValidation ?
SerializeValidationRules(viewModelConverter) :
null;

// create result object
var result = new JObject();
result["viewModel"] = viewModelToken;
Expand All @@ -162,9 +156,6 @@ public void BuildViewModel(IDotvvmRequestContext context, object? commandResult)
result["renderedResources"] = JArray.FromObject(context.ResourceManager.GetNamedResourcesInOrder().Select(r => r.Name));
}

// TODO: do not send on postbacks
if (validationRules?.Count > 0) result["validationRules"] = validationRules;

if (commandResult != null) result["commandResult"] = WriteCommandData(commandResult, serializer, "the command result");
AddCustomPropertiesIfAny(context, serializer, result);

Expand Down Expand Up @@ -264,28 +255,6 @@ public JObject BuildResourcesJson(IDotvvmRequestContext context, Func<string, bo
return resourceObj;
}

/// <summary>
/// Serializes the validation rules.
/// </summary>
private JObject SerializeValidationRules(ViewModelJsonConverter viewModelConverter)
{
var validationRules = new JObject();
foreach (var map in viewModelConverter.UsedSerializationMaps)
{
var rule = new JObject();

foreach (var property in map.Properties)
{
if (property.ValidationRules.Count > 0 && property.ClientValidationRules.Any())
rule[property.Name] = JToken.FromObject(property.ClientValidationRules);
}
if (rule.Count > 0) validationRules[map.Type.GetTypeHash()] = rule;
}
return validationRules;
}



/// <summary>
/// Serializes the redirect action.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Reflection;
using System.Threading;
using DotVVM.Framework.Configuration;
using DotVVM.Framework.Runtime;
using DotVVM.Framework.Utils;
using FastExpressionCompiler;
using Newtonsoft.Json.Linq;
Expand All @@ -18,13 +19,17 @@ public class ViewModelTypeMetadataSerializer : IViewModelTypeMetadataSerializer
{
private readonly IViewModelSerializationMapper viewModelSerializationMapper;
private readonly bool debug;
private static readonly ConcurrentDictionary<ViewModelSerializationMapWithCulture, ObjectMetadataWithDependencies> cachedObjectMetadata = new ConcurrentDictionary<ViewModelSerializationMapWithCulture, ObjectMetadataWithDependencies>();
private static readonly ConcurrentDictionary<Type, JObject> cachedEnumMetadata = new ConcurrentDictionary<Type, JObject>();
private readonly bool serializeValidationRules;
private readonly ConcurrentDictionary<ViewModelSerializationMapWithCulture, ObjectMetadataWithDependencies> cachedObjectMetadata = new ConcurrentDictionary<ViewModelSerializationMapWithCulture, ObjectMetadataWithDependencies>();
private readonly ConcurrentDictionary<Type, JObject> cachedEnumMetadata = new ConcurrentDictionary<Type, JObject>();

public ViewModelTypeMetadataSerializer(IViewModelSerializationMapper viewModelSerializationMapper, DotvvmConfiguration? config = null)
{
this.viewModelSerializationMapper = viewModelSerializationMapper;
this.debug = config != null && config.Debug;
this.serializeValidationRules = config is null || config.ClientSideValidation;

HotReloadMetadataUpdateHandler.TypeMetadataSerializer.Add(new(this));
}

public JObject SerializeTypeMetadata(IEnumerable<ViewModelSerializationMap> usedSerializationMaps, ISet<string>? ignoredTypes = null)
Expand Down Expand Up @@ -128,7 +133,7 @@ private ObjectMetadataWithDependencies BuildObjectTypeMetadata(ViewModelSerializ
prop["update"] = "no";
}

if (property.ValidationRules.Any() && property.ClientValidationRules.Any())
if (serializeValidationRules && property.ValidationRules.Any() && property.ClientValidationRules.Any())
{
prop["validationRules"] = JToken.FromObject(property.ClientValidationRules);
}
Expand Down Expand Up @@ -275,7 +280,7 @@ public override int GetHashCode()
}

/// <summary> Clear caches for the specified types </summary>
internal static void ClearCaches(Type[] types)
internal void ClearCaches(Type[] types)
{
foreach (var t in types)
cachedEnumMetadata.TryRemove(t, out _);
Expand Down
31 changes: 31 additions & 0 deletions src/Tests/ViewModel/ViewModelTypeMetadataSerializerTests.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using CheckTestOutput;
using DotVVM.Framework.Configuration;
using DotVVM.Framework.ViewModel;
using DotVVM.Framework.Utils;
using DotVVM.Framework.ViewModel.Serialization;
using DotVVM.Framework.ViewModel.Validation;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using DotVVM.Framework.Testing;

namespace DotVVM.Framework.Tests.ViewModel
{
Expand Down Expand Up @@ -74,6 +77,34 @@ public void ViewModelTypeMetadata_TypeMetadata()
});
}

[TestMethod]
public void ViewModelTypeMetadata_ValidationRules()
{
CultureUtils.RunWithCulture("en-US", () => {
var typeMetadataSerializer = new ViewModelTypeMetadataSerializer(mapper);
var result = typeMetadataSerializer.SerializeTypeMetadata(new[] { mapper.GetMap(typeof(TestViewModel)) });
var rules = XAssert.IsType<JArray>(result[typeof(TestViewModel).GetTypeHash()]["properties"]["ServerToClient"]["validationRules"]);
XAssert.Single(rules);
Assert.AreEqual("required", rules[0]["ruleName"].Value<string>());
Assert.AreEqual("ServerToClient is required!", rules[0]["errorMessage"].Value<string>());
});
}

[TestMethod]
public void ViewModelTypeMetadata_ValidationDisabled()
{
CultureUtils.RunWithCulture("en-US", () => {
var config = DotvvmTestHelper.CreateConfiguration();
config.ClientSideValidation = false;
var typeMetadataSerializer = new ViewModelTypeMetadataSerializer(mapper, config);
var result = typeMetadataSerializer.SerializeTypeMetadata(new[] { mapper.GetMap(typeof(TestViewModel)) });
XAssert.Null(result[typeof(TestViewModel).GetTypeHash()]["properties"]["ServerToClient"]["validationRules"]);
});
}

[Flags]
enum SampleEnum
{
Expand Down

0 comments on commit 5f8a459

Please sign in to comment.