fix
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
namespace MyOffice.Web.Infrastructure.Attributes;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class DefaultFromBodyAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
public class GlobalModelStateValidatorAttribute : ActionFilterAttribute
|
||||
{
|
||||
private readonly ProblemDetailsFactory _problemDetailsFactory;
|
||||
|
||||
public GlobalModelStateValidatorAttribute(ProblemDetailsFactory problemDetailsFactory)
|
||||
{
|
||||
_problemDetailsFactory = problemDetailsFactory;
|
||||
}
|
||||
|
||||
public override void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
if (!context.ModelState.IsValid)
|
||||
{
|
||||
context.Result = new ObjectResult(_problemDetailsFactory.CreateValidationProblemDetails(context.HttpContext, context.ModelState))
|
||||
{
|
||||
StatusCode = StatusCodes.Status400BadRequest
|
||||
};
|
||||
}
|
||||
|
||||
base.OnActionExecuting(context);
|
||||
}
|
||||
}
|
||||
public class DefaultFromBodyBindingConvention : IActionModelConvention
|
||||
{
|
||||
public void Apply(ActionModel action)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(action));
|
||||
}
|
||||
|
||||
if (action.Controller.Attributes.Any(a => a is DefaultFromBodyAttribute))
|
||||
{
|
||||
foreach (var parameter in action.Parameters)
|
||||
{
|
||||
var paramType = parameter.ParameterInfo.ParameterType;
|
||||
var isSimpleType = paramType.IsPrimitive
|
||||
|| paramType.IsEnum
|
||||
|| paramType == typeof(string)
|
||||
|| paramType == typeof(decimal);
|
||||
|
||||
if (!isSimpleType)
|
||||
{
|
||||
parameter.BindingInfo = parameter.BindingInfo ?? new BindingInfo();
|
||||
parameter.BindingInfo.BindingSource = BindingSource.Body;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
namespace MyOffice.Web.Infrastructure;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
public class CustomProblemDetailsFactory : ProblemDetailsFactory
|
||||
{
|
||||
private readonly ApiBehaviorOptions options;
|
||||
private readonly JsonOptions jsonOptions;
|
||||
|
||||
public CustomProblemDetailsFactory(IOptions<ApiBehaviorOptions> options, IOptions<JsonOptions> jsonOptions)
|
||||
{
|
||||
this.options = options?.Value ?? throw new ArgumentNullException(nameof(options));
|
||||
this.jsonOptions = jsonOptions?.Value ?? throw new ArgumentNullException(nameof(jsonOptions));
|
||||
}
|
||||
|
||||
public override ProblemDetails CreateProblemDetails(
|
||||
HttpContext httpContext,
|
||||
int? statusCode = null,
|
||||
string? title = null,
|
||||
string? type = null,
|
||||
string? detail = null,
|
||||
string? instance = null)
|
||||
{
|
||||
statusCode ??= 500;
|
||||
|
||||
var problemDetails = new ProblemDetails
|
||||
{
|
||||
Status = statusCode,
|
||||
Title = title,
|
||||
Type = type,
|
||||
Detail = detail,
|
||||
Instance = instance,
|
||||
};
|
||||
|
||||
ApplyProblemDetailsDefaults(httpContext, problemDetails, statusCode.Value);
|
||||
|
||||
return problemDetails;
|
||||
}
|
||||
|
||||
public override ValidationProblemDetails CreateValidationProblemDetails(
|
||||
HttpContext httpContext,
|
||||
ModelStateDictionary modelStateDictionary,
|
||||
int? statusCode = null,
|
||||
string? title = null,
|
||||
string? type = null,
|
||||
string? detail = null,
|
||||
string? instance = null)
|
||||
{
|
||||
if (modelStateDictionary == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(modelStateDictionary));
|
||||
}
|
||||
|
||||
statusCode ??= 400;
|
||||
|
||||
var errors = modelStateDictionary
|
||||
.Where(x => x.Value?.Errors.Any() == true)
|
||||
.ToDictionary(
|
||||
kvp => jsonOptions?.JsonSerializerOptions?.PropertyNamingPolicy?.ConvertName(kvp.Key) ?? kvp.Key,
|
||||
kvp => kvp.Value!.Errors.Select(x => x.ErrorMessage).ToArray()
|
||||
);
|
||||
|
||||
var problemDetails = new ValidationProblemDetails(errors)
|
||||
{
|
||||
Status = statusCode,
|
||||
Type = type,
|
||||
Detail = detail,
|
||||
Instance = instance,
|
||||
};
|
||||
|
||||
if (title != null)
|
||||
{
|
||||
// For validation problem details, don't overwrite the default title with null.
|
||||
problemDetails.Title = title;
|
||||
}
|
||||
|
||||
ApplyProblemDetailsDefaults(httpContext, problemDetails, statusCode.Value);
|
||||
|
||||
return problemDetails;
|
||||
}
|
||||
|
||||
private void ApplyProblemDetailsDefaults(HttpContext httpContext, ProblemDetails problemDetails, int statusCode)
|
||||
{
|
||||
problemDetails.Status ??= statusCode;
|
||||
|
||||
if (options.ClientErrorMapping.TryGetValue(statusCode, out var clientErrorData))
|
||||
{
|
||||
problemDetails.Title ??= clientErrorData.Title;
|
||||
problemDetails.Type ??= clientErrorData.Link;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user