");
WriteText(p.Key);
Write(":");
- if (p.Value is JObject)
+ if (p.Value is null)
+ {
+ WriteText("null");
+ }
+ else if (p.Value is JObject)
{
ObjectBrowser((JObject)p.Value);
}
@@ -360,9 +370,9 @@ class IgnoreStuffJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) =>
objectType.IsDelegate();
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) =>
+ public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) =>
throw new NotImplementedException();
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
writer.WriteValue("
");
}
diff --git a/src/Framework/Framework/Hosting/ModelState.cs b/src/Framework/Framework/Hosting/ModelState.cs
index d7a195e489..03e685895e 100644
--- a/src/Framework/Framework/Hosting/ModelState.cs
+++ b/src/Framework/Framework/Hosting/ModelState.cs
@@ -13,7 +13,7 @@ public class ModelState
///
/// Gets the validation target path relative to the command target.
///
- internal string ValidationTargetPath { get; set; }
+ internal string? ValidationTargetPath { get; set; }
///
/// Gets the object that was validated.
diff --git a/src/Framework/Framework/ResourceManagement/ClientGlobalize/JQueryGlobalizeScriptCreator.cs b/src/Framework/Framework/ResourceManagement/ClientGlobalize/JQueryGlobalizeScriptCreator.cs
index 4414b52f55..795265e657 100644
--- a/src/Framework/Framework/ResourceManagement/ClientGlobalize/JQueryGlobalizeScriptCreator.cs
+++ b/src/Framework/Framework/ResourceManagement/ClientGlobalize/JQueryGlobalizeScriptCreator.cs
@@ -133,11 +133,11 @@ private static JObject CreateNumberInfoJson(NumberFormatInfo ni)
var jobj = JObject.FromObject(numberFormat);
jobj[","] = ni.NumberGroupSeparator;
jobj["."] = ni.NumberDecimalSeparator;
- jobj["percent"][","] = ni.PercentGroupSeparator;
- jobj["percent"]["."] = ni.PercentDecimalSeparator;
+ jobj["percent"]![","] = ni.PercentGroupSeparator;
+ jobj["percent"]!["."] = ni.PercentDecimalSeparator;
- jobj["currency"][","] = ni.CurrencyGroupSeparator;
- jobj["currency"]["."] = ni.CurrencyDecimalSeparator;
+ jobj["currency"]![","] = ni.CurrencyGroupSeparator;
+ jobj["currency"]!["."] = ni.CurrencyDecimalSeparator;
return jobj;
}
diff --git a/src/Framework/Framework/ResourceManagement/ReflectionAssemblyJsonConverter.cs b/src/Framework/Framework/ResourceManagement/ReflectionAssemblyJsonConverter.cs
index c3d90e3a74..18d89d6cac 100644
--- a/src/Framework/Framework/ResourceManagement/ReflectionAssemblyJsonConverter.cs
+++ b/src/Framework/Framework/ResourceManagement/ReflectionAssemblyJsonConverter.cs
@@ -13,7 +13,7 @@ public class ReflectionAssemblyJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => typeof(Assembly).IsAssignableFrom(objectType);
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
if (reader.Value is string name)
{
@@ -22,9 +22,9 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
else throw new NotSupportedException();
}
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
- writer.WriteValue(((Assembly)value).GetName().ToString());
+ writer.WriteValue(((Assembly?)value)?.GetName().ToString());
}
}
@@ -32,7 +32,7 @@ public class ReflectionTypeJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => typeof(Type).IsAssignableFrom(objectType);
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
if (reader.Value is string name)
{
@@ -41,8 +41,14 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
else throw new NotSupportedException();
}
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
+ if (value is null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
var t = ((Type)value);
if (t.Assembly == typeof(string).Assembly)
writer.WriteValue(t.FullName);
@@ -54,7 +60,7 @@ public class DotvvmTypeDescriptorJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => typeof(ITypeDescriptor).IsAssignableFrom(objectType);
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
if (reader.Value is string name)
{
@@ -63,8 +69,13 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
else throw new NotSupportedException();
}
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
+ if (value is null)
+ {
+ writer.WriteNull();
+ return;
+ }
var t = ((ITypeDescriptor)value);
var coreAssembly = typeof(string).Assembly.GetName().Name;
var assembly = t.Assembly?.Split(new char[] { ',' }, 2)[0];
diff --git a/src/Framework/Framework/ResourceManagement/ResourceRepositoryJsonConverter.cs b/src/Framework/Framework/ResourceManagement/ResourceRepositoryJsonConverter.cs
index 24839da0c1..894a5b9d11 100644
--- a/src/Framework/Framework/ResourceManagement/ResourceRepositoryJsonConverter.cs
+++ b/src/Framework/Framework/ResourceManagement/ResourceRepositoryJsonConverter.cs
@@ -34,7 +34,7 @@ public override bool CanConvert(Type objectType)
return null;
}
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
var jobj = JObject.Load(reader);
var repo = existingValue as DotvvmResourceRepository ?? new DotvvmResourceRepository();
@@ -42,15 +42,15 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
{
if (resourceTypeAliases.FirstOrDefault(x => x.name == prop.Key) is var r && r.type != null)
{
- DeserializeResources((JObject)prop.Value, r.type, serializer, repo);
+ DeserializeResources((JObject)prop.Value.NotNull(), r.type, serializer, repo);
}
else if (CompiledAssemblyCache.Instance!.FindType(prop.Key) is Type resourceType)
{
- DeserializeResources((JObject)prop.Value, resourceType, serializer, repo);
+ DeserializeResources((JObject)prop.Value.NotNull(), resourceType, serializer, repo);
}
else if (UnknownResourceType != null)
{
- DeserializeResources((JObject)prop.Value, UnknownResourceType, serializer, repo);
+ DeserializeResources((JObject)prop.Value.NotNull(), UnknownResourceType, serializer, repo);
}
else
throw new NotSupportedException(string.Format("resource collection name {0} is not supported", prop.Key));
@@ -64,7 +64,7 @@ void DeserializeResources(JObject jobj, Type resourceType, JsonSerializer serial
{
try
{
- var resource = (IResource)serializer.Deserialize(resObj.Value.CreateReader(), resourceType);
+ var resource = (IResource)serializer.Deserialize(resObj.Value!.CreateReader(), resourceType).NotNull();
if (resource is LinkResourceBase linkResource)
{
if (linkResource.Location == null)
@@ -82,8 +82,13 @@ void DeserializeResources(JObject jobj, Type resourceType, JsonSerializer serial
}
}
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
writer.WriteStartObject();
var resources = value as DotvvmResourceRepository ?? throw new NotSupportedException();
foreach (var (name, group) in (
@@ -110,8 +115,8 @@ orderby name
public class DeserializationErrorResource : ResourceBase
{
public Exception Error { get; }
- public JToken Json { get; set; }
- public DeserializationErrorResource(Exception error, JToken json) : base(ResourceRenderPosition.Head)
+ public JToken? Json { get; set; }
+ public DeserializationErrorResource(Exception error, JToken? json) : base(ResourceRenderPosition.Head)
{
this.Error = error;
this.Json = json;
@@ -119,7 +124,7 @@ public DeserializationErrorResource(Exception error, JToken json) : base(Resourc
public override void Render(IHtmlWriter writer, IDotvvmRequestContext context, string resourceName)
{
- throw new NotSupportedException($"Resource could not be deserialized from '{Json.ToString()}': \n{Error}");
+ throw new NotSupportedException($"Resource could not be deserialized from '{(Json is null ? "null" : Json.ToString())}': \n{Error}");
}
}
}
diff --git a/src/Framework/Framework/Routing/RouteTableJsonConverter.cs b/src/Framework/Framework/Routing/RouteTableJsonConverter.cs
index 0cce01e1fa..bd3e6154fe 100644
--- a/src/Framework/Framework/Routing/RouteTableJsonConverter.cs
+++ b/src/Framework/Framework/Routing/RouteTableJsonConverter.cs
@@ -8,6 +8,7 @@
using System.Threading.Tasks;
using DotVVM.Framework.Hosting;
using System.Diagnostics.CodeAnalysis;
+using DotVVM.Framework.Utils;
namespace DotVVM.Framework.Routing
{
@@ -15,29 +16,34 @@ public class RouteTableJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => objectType == typeof(DotvvmRouteTable);
- public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
var rt = existingValue as DotvvmRouteTable;
if (rt == null) return null;
foreach (var prop in (JObject)JObject.ReadFrom(reader))
{
- var route = (JObject)prop.Value;
+ var route = (JObject)prop.Value.NotNull();
try
{
- rt.Add(prop.Key, route["url"].Value(), route["virtualPath"].Value(), route["defaultValues"].ToObject>());
+ rt.Add(prop.Key, route["url"].NotNull("route.url is required").Value(), (route["virtualPath"]?.Value()).NotNull("route.virtualPath is required"), route["defaultValues"]?.ToObject>());
}
catch (Exception error)
{
- rt.Add(prop.Key, new ErrorRoute(route["url"].Value(), route["virtualPath"].Value(), prop.Key, route["defaultValues"].ToObject>(), error));
+ rt.Add(prop.Key, new ErrorRoute(route["url"]?.Value(), route["virtualPath"]?.Value(), prop.Key, route["defaultValues"]?.ToObject>(), error));
}
}
return rt;
}
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => WriteJson(writer, (DotvvmRouteTable)value, serializer);
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) => WriteJson(writer, (DotvvmRouteTable?)value, serializer);
- public void WriteJson(JsonWriter writer, DotvvmRouteTable value, JsonSerializer serializer)
+ public void WriteJson(JsonWriter writer, DotvvmRouteTable? value, JsonSerializer serializer)
{
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
writer.WriteStartObject();
foreach (var route in value)
{
@@ -55,7 +61,8 @@ sealed class ErrorRoute : RouteBase
{
private readonly Exception error;
- public ErrorRoute(string url, string virtualPath, string name, IDictionary? defaultValues, Exception error) : base(url, virtualPath, name, defaultValues)
+ public ErrorRoute(string? url, string? virtualPath, string? name, IDictionary? defaultValues, Exception error)
+ : base(url ?? "", virtualPath ?? "", name ?? "", defaultValues)
{
this.error = error;
}
diff --git a/src/Framework/Framework/Runtime/Commands/CommandResolver.cs b/src/Framework/Framework/Runtime/Commands/CommandResolver.cs
index 515888da4d..4936fbfcef 100644
--- a/src/Framework/Framework/Runtime/Commands/CommandResolver.cs
+++ b/src/Framework/Framework/Runtime/Commands/CommandResolver.cs
@@ -16,7 +16,7 @@ public class CommandResolver
///
/// Resolves the command called on the DotvvmControl.
///
- public ActionInfo GetFunction(DotvvmControl? targetControl, DotvvmControl viewRootControl, IDotvvmRequestContext context, string[] path, string commandId, Func[] args)
+ public ActionInfo GetFunction(DotvvmControl? targetControl, DotvvmControl viewRootControl, IDotvvmRequestContext context, string[] path, string commandId, Func[] args)
{
// event validation
var validationTargetPath = context.ModelState.ValidationTargetPath;
@@ -51,7 +51,7 @@ public ActionInfo GetFunction(DotvvmControl? targetControl, DotvvmControl viewRo
///
/// Resolves the command called on the ViewModel.
///
- public ActionInfo GetFunction(DotvvmControl viewRootControl, IDotvvmRequestContext context, string[] path, string command, Func[] args)
+ public ActionInfo GetFunction(DotvvmControl viewRootControl, IDotvvmRequestContext context, string[] path, string command, Func[] args)
{
return GetFunction(null, viewRootControl, context, path, command, args);
}
diff --git a/src/Framework/Framework/Runtime/Commands/EventValidator.cs b/src/Framework/Framework/Runtime/Commands/EventValidator.cs
index f91467d556..d0cbfe1ba7 100644
--- a/src/Framework/Framework/Runtime/Commands/EventValidator.cs
+++ b/src/Framework/Framework/Runtime/Commands/EventValidator.cs
@@ -19,7 +19,7 @@ public class EventValidator
///
/// Validates the command.
///
- public FindBindingResult ValidateCommand(string[] path, string commandId, DotvvmControl viewRootControl, string validationTargetPath)
+ public FindBindingResult ValidateCommand(string[] path, string commandId, DotvvmControl viewRootControl, string? validationTargetPath)
{
// find the binding
var result = FindCommandBinding(path, commandId, viewRootControl, validationTargetPath);
@@ -175,13 +175,13 @@ private FindBindingResult FindCommandBinding(string[] path, string commandId,
/// Finds the binding of the specified type on the specified viewmodel path.
///
private FindBindingResult FindCommandBinding(string[] path, string commandId,
- DotvvmBindableObject viewRootControl, string validationTargetPath)
+ DotvvmBindableObject viewRootControl, string? validationTargetPath)
=> FindCommandBinding(path, commandId, viewRootControl, null, validationTargetPath, false);
///
/// Validates the control command.
///
- public FindBindingResult ValidateControlCommand(string[] path, string commandId, DotvvmControl viewRootControl, DotvvmControl targetControl, string validationTargetPath)
+ public FindBindingResult ValidateControlCommand(string[] path, string commandId, DotvvmControl viewRootControl, DotvvmControl targetControl, string? validationTargetPath)
{
// find the binding
var result = FindControlCommandBinding(path, commandId, viewRootControl, targetControl, validationTargetPath);
@@ -196,7 +196,7 @@ public FindBindingResult ValidateControlCommand(string[] path, string commandId,
/// Finds the binding of the specified type on the specified viewmodel path.
///
private FindBindingResult FindControlCommandBinding(string[] path, string commandId,
- DotvvmControl viewRootControl, DotvvmBindableObject targetControl, string validationTargetPath)
+ DotvvmControl viewRootControl, DotvvmBindableObject targetControl, string? validationTargetPath)
=> FindCommandBinding(path, commandId, viewRootControl, targetControl, validationTargetPath, true);
diff --git a/src/Framework/Framework/Storage/FileSystemReturnedFileStorage.cs b/src/Framework/Framework/Storage/FileSystemReturnedFileStorage.cs
index 647193eca2..3ab0ab2d93 100644
--- a/src/Framework/Framework/Storage/FileSystemReturnedFileStorage.cs
+++ b/src/Framework/Framework/Storage/FileSystemReturnedFileStorage.cs
@@ -111,7 +111,7 @@ public Task GetFileAsync(Guid id)
{
var metadataJson = File.ReadAllText(GetMetadataFilePath(id), Encoding.UTF8);
var settings = DefaultSerializerSettingsProvider.Instance.Settings;
- var metadata = JsonConvert.DeserializeObject(metadataJson, settings);
+ var metadata = JsonConvert.DeserializeObject(metadataJson, settings).NotNull();
var stream = new FileStream(GetDataFilePath(id), FileMode.Open, FileAccess.Read);
diff --git a/src/Framework/Framework/Utils/FunctionalExtensions.cs b/src/Framework/Framework/Utils/FunctionalExtensions.cs
index e2b08413b7..7dd383c860 100644
--- a/src/Framework/Framework/Utils/FunctionalExtensions.cs
+++ b/src/Framework/Framework/Utils/FunctionalExtensions.cs
@@ -107,6 +107,17 @@ public static T NotNull([NotNull] this T? target, string message = "Unexpecte
public static SortedDictionary ToSorted(this IDictionary d, IComparer? c = null)
where K: notnull =>
new(d, c ?? Comparer.Default);
+
+ internal static IEnumerable WhereNotNull(this IEnumerable enumerable) where T : class =>
+ enumerable.Where(x => x != null)!;
+ internal static IEnumerable WhereNotNull(this IEnumerable> enumerable) where T : struct
+ {
+ foreach (var x in enumerable)
+ {
+ if (x.HasValue)
+ yield return x.Value;
+ }
+ }
}
sealed class ObjectWithComparer : IEquatable>, IEquatable
diff --git a/src/Framework/Framework/Utils/JsonUtils.cs b/src/Framework/Framework/Utils/JsonUtils.cs
index 95100cb41e..09bcbae835 100644
--- a/src/Framework/Framework/Utils/JsonUtils.cs
+++ b/src/Framework/Framework/Utils/JsonUtils.cs
@@ -56,7 +56,7 @@ public static JObject Diff(JObject source, JObject target, bool nullOnRemoved =
else
{
var targetJson = $@"{{""Time"": ""{item.Value}""}}";
- targetTime = JObject.Parse(targetJson)["Time"].ToObject();
+ targetTime = JObject.Parse(targetJson)["Time"]!.ToObject();
}
if (!sourceTime.Equals(targetTime))
@@ -174,7 +174,7 @@ public static void Patch(JObject target, JObject diff, bool removeOnNull = false
{
var val = target[prop.Key];
if (val == null) target[prop.Key] = prop.Value;
- else if (prop.Value.Type == JTokenType.Null && removeOnNull || (prop.Value as JConstructor)?.Name == "$rm") target.Remove(prop.Key);
+ else if (prop.Value!.Type == JTokenType.Null && removeOnNull || (prop.Value as JConstructor)?.Name == "$rm") target.Remove(prop.Key);
else target[prop.Key] = PatchItem(val, prop.Value, removeOnNull);
}
}
diff --git a/src/Framework/Framework/Utils/ReflectionUtils.cs b/src/Framework/Framework/Utils/ReflectionUtils.cs
index 1b26d35c02..bf5e8ea0ef 100644
--- a/src/Framework/Framework/Utils/ReflectionUtils.cs
+++ b/src/Framework/Framework/Utils/ReflectionUtils.cs
@@ -555,7 +555,7 @@ public static Type GetResultType(this MemberInfo member) =>
}
else if (EnumInfo.IsFlags)
{
- return JsonConvert.DeserializeObject(JsonConvert.ToString(instance.Value));
+ return JsonConvert.DeserializeObject(JsonConvert.ToString(instance.Value))!;
}
else
{
diff --git a/src/Framework/Framework/ViewModel/Serialization/CustomPrimitiveTypeJsonConverter.cs b/src/Framework/Framework/ViewModel/Serialization/CustomPrimitiveTypeJsonConverter.cs
index 377bf56a5d..7529850f24 100644
--- a/src/Framework/Framework/ViewModel/Serialization/CustomPrimitiveTypeJsonConverter.cs
+++ b/src/Framework/Framework/ViewModel/Serialization/CustomPrimitiveTypeJsonConverter.cs
@@ -15,7 +15,7 @@ public override bool CanConvert(Type objectType)
return ReflectionUtils.IsCustomPrimitiveType(objectType);
}
- public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
if (reader.TokenType is JsonToken.String
or JsonToken.Boolean
@@ -41,7 +41,7 @@ or JsonToken.Float
}
}
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value == null)
{
diff --git a/src/Framework/Framework/ViewModel/Serialization/DefaultViewModelSerializer.cs b/src/Framework/Framework/ViewModel/Serialization/DefaultViewModelSerializer.cs
index 3580e99997..dddffd8e26 100644
--- a/src/Framework/Framework/ViewModel/Serialization/DefaultViewModelSerializer.cs
+++ b/src/Framework/Framework/ViewModel/Serialization/DefaultViewModelSerializer.cs
@@ -61,9 +61,9 @@ public string SerializeViewModel(IDotvvmRequestContext context)
var timer = ValueStopwatch.StartNew();
context.ViewModelJson ??= new JObject();
- if (SendDiff && context.ReceivedViewModelJson != null && context.ViewModelJson["viewModel"] != null)
+ if (SendDiff && context.ReceivedViewModelJson?["viewModel"] is JObject receivedVM && context.ViewModelJson["viewModel"] is JObject responseVM)
{
- context.ViewModelJson["viewModelDiff"] = JsonUtils.Diff((JObject)context.ReceivedViewModelJson["viewModel"], (JObject)context.ViewModelJson["viewModel"], false, i => ShouldIncludeProperty(i.TypeId, i.Property));
+ context.ViewModelJson["viewModelDiff"] = JsonUtils.Diff(receivedVM, responseVM, false, i => ShouldIncludeProperty(i.TypeId, i.Property));
context.ViewModelJson.Remove("viewModel");
}
var result = context.ViewModelJson.ToString(JsonFormatting);
@@ -117,7 +117,7 @@ public void BuildViewModel(IDotvvmRequestContext context, object? commandResult)
{
throw new SerializationException(true, context.ViewModel!.GetType(), writer.Path, ex);
}
- var viewModelToken = writer.Token;
+ var viewModelToken = writer.Token.NotNull();
string? viewModelCacheId = null;
if (context.Configuration.ExperimentalFeatures.ServerSideViewModelCache.IsEnabledForRoute(context.Route?.RouteName))
@@ -177,13 +177,13 @@ public void BuildViewModel(IDotvvmRequestContext context, object? commandResult)
private JObject SerializeTypeMetadata(IDotvvmRequestContext context, ViewModelJsonConverter viewModelJsonConverter)
{
- var knownTypeIds = context.ReceivedViewModelJson?["knownTypeMetadata"]?.Values().ToImmutableHashSet();
+ var knownTypeIds = context.ReceivedViewModelJson?["knownTypeMetadata"]?.Values().WhereNotNull().ToImmutableHashSet();
return viewModelTypeMetadataSerializer.SerializeTypeMetadata(viewModelJsonConverter.UsedSerializationMaps, knownTypeIds);
}
public void AddNewResources(IDotvvmRequestContext context)
{
- var renderedResources = new HashSet(context.ReceivedViewModelJson?["renderedResources"]?.Values() ?? new string[] { });
+ var renderedResources = new HashSet(context.ReceivedViewModelJson?["renderedResources"]?.Values().WhereNotNull() ?? new string[] { });
var resourcesObject = BuildResourcesJson(context, rn => !renderedResources.Contains(rn));
if (resourcesObject.Count > 0)
context.ViewModelJson!["resources"] = resourcesObject;
@@ -235,7 +235,7 @@ private static JToken WriteCommandData(object? data, JsonSerializer serializer,
{
throw new SerializationException(true, data?.GetType(), writer.Path, ex);
}
- return writer.Token;
+ return writer.Token.NotNull();
}
protected virtual JsonSerializer CreateJsonSerializer() => DefaultSerializerSettingsProvider.Instance.Settings.Apply(JsonSerializer.Create);
@@ -333,35 +333,34 @@ public void PopulateViewModel(IDotvvmRequestContext context, string serializedPo
// get properties
var data = context.ReceivedViewModelJson = JObject.Parse(serializedPostData);
JObject viewModelToken;
- if (data["viewModelCacheId"] != null)
+ if (data["viewModelCacheId"]?.Value() is string viewModelCacheId)
{
if (!context.Configuration.ExperimentalFeatures.ServerSideViewModelCache.IsEnabledForRoute(context.Route?.RouteName))
{
throw new InvalidOperationException("The server-side viewmodel caching is not enabled for the current route!");
}
- viewModelToken = viewModelServerCache.TryRestoreViewModel(context, (string)data["viewModelCacheId"], (JObject)data["viewModelDiff"]);
+ viewModelToken = viewModelServerCache.TryRestoreViewModel(context, viewModelCacheId, (JObject)data["viewModelDiff"]!);
data["viewModel"] = viewModelToken;
}
else
{
- viewModelToken = (JObject)data["viewModel"];
+ viewModelToken = (JObject)data["viewModel"]!;
}
// load CSRF token
context.CsrfToken = viewModelToken["$csrfToken"]?.Value();
ViewModelJsonConverter viewModelConverter;
- if (viewModelToken["$encryptedValues"] != null)
+ if (viewModelToken["$encryptedValues"]?.Value() is string encryptedValuesString)
{
// load encrypted values
- var encryptedValuesString = viewModelToken["$encryptedValues"].Value();
viewModelConverter = new ViewModelJsonConverter(IsPostBack(context), viewModelMapper, context.Services, JObject.Parse(viewModelProtector.Unprotect(encryptedValuesString, context)));
}
else viewModelConverter = new ViewModelJsonConverter(IsPostBack(context), viewModelMapper, context.Services);
// get validation path
- context.ModelState.ValidationTargetPath = (string)data["validationTargetPath"];
+ context.ModelState.ValidationTargetPath = (string?)data["validationTargetPath"];
// populate the ViewModel
var serializer = CreateJsonSerializer();
@@ -390,12 +389,12 @@ public void PopulateViewModel(IDotvvmRequestContext context, string serializedPo
{
// get properties
var data = context.ReceivedViewModelJson ?? throw new NotSupportedException("Could not find ReceivedViewModelJson in request context.");
- var path = data["currentPath"].Values().ToArray();
- var command = data["command"].Value();
+ var path = data["currentPath"].NotNull("currentPath is required").Values().ToArray();
+ var command = data["command"].NotNull("command is required").Value();
var controlUniqueId = data["controlUniqueId"]?.Value();
var args = data["commandArgs"] is JArray argsJson ?
- argsJson.Select(a => (Func)(t => a.ToObject(t))).ToArray() :
- new Func[0];
+ argsJson.Select(a => (Func)(t => a.ToObject(t))).ToArray() :
+ new Func[0];
// empty command
if (string.IsNullOrEmpty(command)) return null;
@@ -408,11 +407,11 @@ public void PopulateViewModel(IDotvvmRequestContext context, string serializedPo
{
throw new Exception(string.Format("The control with ID '{0}' was not found!", controlUniqueId));
}
- return commandResolver.GetFunction(target, view, context, path, command, args);
+ return commandResolver.GetFunction(target, view, context, path!, command, args);
}
else
{
- return commandResolver.GetFunction(view, context, path, command, args);
+ return commandResolver.GetFunction(view, context, path!, command, args);
}
}
diff --git a/src/Framework/Framework/ViewModel/Serialization/DotvvmByteArrayConverter.cs b/src/Framework/Framework/ViewModel/Serialization/DotvvmByteArrayConverter.cs
index 9451357cb7..4df3b330c0 100644
--- a/src/Framework/Framework/ViewModel/Serialization/DotvvmByteArrayConverter.cs
+++ b/src/Framework/Framework/ViewModel/Serialization/DotvvmByteArrayConverter.cs
@@ -9,7 +9,7 @@ namespace DotVVM.Framework.ViewModel.Serialization
{
public class DotvvmByteArrayConverter : JsonConverter
{
- public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
@@ -40,7 +40,7 @@ public class DotvvmByteArrayConverter : JsonConverter
}
}
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value == null)
{
diff --git a/src/Framework/Framework/ViewModel/Serialization/DotvvmDateOnlyConverter.cs b/src/Framework/Framework/ViewModel/Serialization/DotvvmDateOnlyConverter.cs
index be84dcb8b3..f7a138e4da 100644
--- a/src/Framework/Framework/ViewModel/Serialization/DotvvmDateOnlyConverter.cs
+++ b/src/Framework/Framework/ViewModel/Serialization/DotvvmDateOnlyConverter.cs
@@ -6,7 +6,7 @@ namespace DotVVM.Framework.ViewModel.Serialization
{
public class DotvvmDateOnlyConverter : JsonConverter
{
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value == null)
{
@@ -35,10 +35,10 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
}
else if (reader.TokenType == JsonToken.Date)
{
- return (DateOnly)reader.Value;
+ return (DateOnly)reader.Value!;
}
else if (reader.TokenType == JsonToken.String
- && DateOnly.TryParseExact((string)reader.Value, "O", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date))
+ && DateOnly.TryParseExact((string)reader.Value!, "O", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date))
{
return date;
}
diff --git a/src/Framework/Framework/ViewModel/Serialization/DotvvmDateTimeConverter.cs b/src/Framework/Framework/ViewModel/Serialization/DotvvmDateTimeConverter.cs
index 381684bac5..daff902202 100644
--- a/src/Framework/Framework/ViewModel/Serialization/DotvvmDateTimeConverter.cs
+++ b/src/Framework/Framework/ViewModel/Serialization/DotvvmDateTimeConverter.cs
@@ -6,7 +6,7 @@ namespace DotVVM.Framework.ViewModel.Serialization
{
public class DotvvmDateTimeConverter : JsonConverter
{
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value == null)
{
@@ -35,10 +35,10 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
}
else if (reader.TokenType == JsonToken.Date)
{
- return (DateTime) reader.Value;
+ return (DateTime) reader.Value!;
}
else if (reader.TokenType == JsonToken.String
- && DateTime.TryParseExact((string)reader.Value, "O", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date))
+ && DateTime.TryParseExact((string)reader.Value!, "O", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date))
{
return date;
}
diff --git a/src/Framework/Framework/ViewModel/Serialization/DotvvmDictionaryConverter.cs b/src/Framework/Framework/ViewModel/Serialization/DotvvmDictionaryConverter.cs
index ecd16b9500..946d20dca2 100644
--- a/src/Framework/Framework/ViewModel/Serialization/DotvvmDictionaryConverter.cs
+++ b/src/Framework/Framework/ViewModel/Serialization/DotvvmDictionaryConverter.cs
@@ -16,10 +16,9 @@ public class DotvvmDictionaryConverter : JsonConverter
private static Type keyValuePairGenericType = typeof(KeyValuePair<,>);
private static Type listGenericType = typeof(List<>);
private static Type dictionaryEntryType = typeof(DictionaryEntry);
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
- var dict = value as IDictionary;
- if (dict == null)
+ if (value is not IDictionary dict)
{
writer.WriteNull();
}
@@ -46,7 +45,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
}
}
- public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
diff --git a/src/Framework/Framework/ViewModel/Serialization/DotvvmTimeOnlyConverter.cs b/src/Framework/Framework/ViewModel/Serialization/DotvvmTimeOnlyConverter.cs
index 2b4a51df19..2a03f596c3 100644
--- a/src/Framework/Framework/ViewModel/Serialization/DotvvmTimeOnlyConverter.cs
+++ b/src/Framework/Framework/ViewModel/Serialization/DotvvmTimeOnlyConverter.cs
@@ -6,7 +6,7 @@ namespace DotVVM.Framework.ViewModel.Serialization
{
public class DotvvmTimeOnlyConverter : JsonConverter
{
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value == null)
{
@@ -35,10 +35,10 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
}
else if (reader.TokenType == JsonToken.Date)
{
- return (TimeOnly)reader.Value;
+ return (TimeOnly)reader.Value!;
}
else if (reader.TokenType == JsonToken.String
- && TimeOnly.TryParseExact((string)reader.Value, "O", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date))
+ && TimeOnly.TryParseExact((string)reader.Value!, "O", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date))
{
return date;
}
diff --git a/src/Framework/Framework/ViewModel/Serialization/ViewModelJsonConverter.cs b/src/Framework/Framework/ViewModel/Serialization/ViewModelJsonConverter.cs
index ab21882fd6..65e34b1ceb 100644
--- a/src/Framework/Framework/ViewModel/Serialization/ViewModelJsonConverter.cs
+++ b/src/Framework/Framework/ViewModel/Serialization/ViewModelJsonConverter.cs
@@ -67,7 +67,7 @@ public override bool CanConvert(Type objectType)
///
/// Reads the JSON representation of the object.
///
- public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
if (existingValue is {})
{
@@ -111,8 +111,13 @@ public override bool CanConvert(Type objectType)
///
/// Writes the JSON representation of the object.
///
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
var evSuppressLevel = evWriter.Value.SuppressedLevel;
try
{
diff --git a/src/Framework/Framework/ViewModel/Serialization/ViewModelTypeMetadataSerializer.cs b/src/Framework/Framework/ViewModel/Serialization/ViewModelTypeMetadataSerializer.cs
index c70c202aa1..88efa3afcc 100644
--- a/src/Framework/Framework/ViewModel/Serialization/ViewModelTypeMetadataSerializer.cs
+++ b/src/Framework/Framework/ViewModel/Serialization/ViewModelTypeMetadataSerializer.cs
@@ -217,7 +217,7 @@ private JObject BuildEnumTypeMetadata(Type type)
var values = new JObject();
foreach (var v in enumValues)
{
- values.Add(ReflectionUtils.ToEnumString(type, v.Name), JToken.FromObject(v.Value));
+ values.Add(ReflectionUtils.ToEnumString(type, v.Name), v.Value is null ? JValue.CreateNull() : JToken.FromObject(v.Value));
}
e["values"] = values;
diff --git a/src/Framework/Testing/ControlTestHelper.cs b/src/Framework/Testing/ControlTestHelper.cs
index c211aca007..2655c0f84f 100644
--- a/src/Framework/Testing/ControlTestHelper.cs
+++ b/src/Framework/Testing/ControlTestHelper.cs
@@ -299,7 +299,7 @@ TestDotvvmRequestContext initialContext
public ControlTestHelper TestHelper { get; }
public string FilePath { get; }
public JObject ResultJson { get; }
- public JObject ViewModelJson => (JObject)ResultJson["viewModel"];
+ public JObject ViewModelJson => (JObject)ResultJson["viewModel"].NotNull();
public dynamic ViewModel => ViewModelJson;
public string OutputString { get; }
public string? HeadResources { get; }
@@ -359,7 +359,7 @@ public async Task RunCommand(string text, Func