Last active
May 23, 2023 11:11
-
-
Save vbilopav/c0dcb26c582025d7e07c7c9116150490 to your computer and use it in GitHub Desktop.
Utility function in C# which validates JSON string against .NET model type by using Newtonsoft Json library.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Newtonsoft.Json.Linq; | |
using Newtonsoft.Json.Serialization; | |
namespace MyNamespace; | |
public static class JsonValidator | |
{ | |
public static bool IsJsonValidType(this string json, Type modelType, out string? message) | |
{ | |
try | |
{ | |
var obj = JObject.Parse(json); | |
foreach (var prop in modelType.GetProperties()) | |
{ | |
var name = prop.Name.ConvertToCamelCase(); | |
Type type = prop.PropertyType; | |
var value = obj[name]; | |
if (value is null) | |
{ | |
message = $"Missing field name: {name}"; | |
return false; | |
} | |
message = value.Type switch | |
{ | |
JTokenType.Array when type.IsListType() || type.IsArray => ValidateList(), | |
JTokenType.Integer when type == typeof(int) || type == typeof(int?) => null, | |
JTokenType.String when type == typeof(string) => null, | |
JTokenType.Boolean when type == typeof(bool) || type == typeof(bool?) => null, | |
JTokenType.Null when type.IsNullableType() => null, | |
JTokenType.Object when type.IsClass => ValidateObject(), | |
_ => $"Field {name} is expected to be of the type {type.Name}, found type: {value.Type.ToString().ConvertToCamelCase()}", | |
}; | |
if (message is not null) | |
{ | |
return false; | |
} | |
string? ValidateList() | |
{ | |
var genericArgs = type.GetGenericArguments(); | |
var listType = genericArgs.Length > 0 ? type.GetGenericArguments()[0] : type.GetElementType()!; | |
foreach (var item in value) | |
{ | |
if (item.Type == JTokenType.String && listType != typeof(string)) | |
{ | |
return $"Field {name} is expected to be a list of strings."; | |
} | |
else if (item.Type == JTokenType.Object) | |
{ | |
if (!item.ToString().IsJsonValidType(listType, out var msg)) | |
{ | |
return msg; | |
} | |
} | |
} | |
return null; | |
} | |
string? ValidateObject() | |
{ | |
if (value != null && !value.ToString().IsJsonValidType(type, out var msg)) | |
{ | |
return msg; | |
} | |
return null; | |
} | |
} | |
message = null; | |
return true; | |
} | |
catch (Exception ex) | |
{ | |
message = ex.Message; | |
return false; | |
} | |
} | |
private static bool IsNullableType(this Type type) => type == typeof(string) || type.IsClass | |
? true | |
: type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); | |
private static bool IsListType(this Type type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>); | |
private static string ConvertToCamelCase(this string name) => CamelCaseResolver.Resolve(name); | |
private class CamelCaseResolver : CamelCaseNamingStrategy | |
{ | |
private static readonly CamelCaseResolver instance = new(); | |
public static string Resolve(string name) => instance.ResolvePropertyName(name); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment