79 lines
3.7 KiB
C#
79 lines
3.7 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
using Microsoft.Extensions.Options;
|
|
using Newtonsoft.Json;
|
|
|
|
namespace gehGassi.Web.Helper
|
|
{
|
|
public class JsonModelBinder : IModelBinder
|
|
{
|
|
private readonly MvcNewtonsoftJsonOptions _options;
|
|
|
|
public JsonModelBinder(IOptions<MvcNewtonsoftJsonOptions> options) =>
|
|
_options = options.Value;
|
|
|
|
public Task BindModelAsync(ModelBindingContext bindingContext)
|
|
{
|
|
if (bindingContext is null)
|
|
throw new ArgumentNullException(nameof(bindingContext));
|
|
|
|
// Test if a value is received
|
|
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
|
|
if (valueProviderResult == ValueProviderResult.None)
|
|
return Task.CompletedTask;
|
|
|
|
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
|
|
|
|
// Get the json serialized value as string
|
|
string serialized = valueProviderResult.FirstValue;
|
|
|
|
// Return a successful binding for empty strings or nulls
|
|
if (String.IsNullOrEmpty(serialized))
|
|
{
|
|
bindingContext.Result = ModelBindingResult.Success(null);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
// Deserialize json string using custom json options defined in startup, if available
|
|
object deserialized = _options?.SerializerSettings is null ?
|
|
JsonConvert.DeserializeObject(serialized, bindingContext.ModelType) :
|
|
JsonConvert.DeserializeObject(serialized, bindingContext.ModelType, _options.SerializerSettings);
|
|
|
|
// Run data annotation validation to validate properties and fields on deserialized model
|
|
var validationResultProps = from property in TypeDescriptor.GetProperties(deserialized).Cast<PropertyDescriptor>()
|
|
from attribute in property.Attributes.OfType<ValidationAttribute>()
|
|
where !attribute.IsValid(property.GetValue(deserialized))
|
|
select new
|
|
{
|
|
Member = property.Name,
|
|
ErrorMessage = attribute.FormatErrorMessage(String.Empty)
|
|
};
|
|
|
|
var validationResultFields = from field in TypeDescriptor.GetReflectionType(deserialized).GetFields().Cast<FieldInfo>()
|
|
from attribute in field.GetCustomAttributes<ValidationAttribute>()
|
|
where !attribute.IsValid(field.GetValue(deserialized))
|
|
select new
|
|
{
|
|
Member = field.Name,
|
|
ErrorMessage = attribute.FormatErrorMessage(String.Empty)
|
|
};
|
|
|
|
// Add the validation results to the model state
|
|
var errors = validationResultFields.Concat(validationResultProps);
|
|
foreach (var validationResultItem in errors)
|
|
bindingContext.ModelState.AddModelError(validationResultItem.Member, validationResultItem.ErrorMessage);
|
|
|
|
// Set successful binding result
|
|
bindingContext.Result = ModelBindingResult.Success(deserialized);
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|
|
}
|