當一個動作接收到錯誤的輸入時,運行時的自動 400 回應特性會生成一個ProblemDetails包含錯誤訊息 ( errors.$[0]) 的 ,如下所示:
"The JSON value could not be converted to CompanyName.Foo.Bar. Path: $ | LineNumber: 0 | BytePositionInLine: 3."
我不想泄露實作細節。
我怎樣才能排除CompanyName.Foo.Bar?
(我使用的是 ASP.NET Core 5,帶有 API 控制器,而不是 MVC。)
uj5u.com熱心網友回復:
想了個辦法。可能有更好/更簡單/更好的方式。
在Startup.ConfigureServices():
services.Configure<ApiBehaviorOptions>(o => {
o.InvalidModelStateResponseFactory = actionContext => {
var problemsDetailsFactory = actionContext.HttpContext.RequestServices.GetRequiredService<ProblemDetailsFactory>();
var modelState = new ModelStateDictionary();
foreach (var key in actionContext.ModelState.Keys) {
var value = actionContext.ModelState[key];
foreach (var error in value.Errors) {
var errorMessage = Regex.Replace(error.ErrorMessage, @"^(The JSON value could not be converted)( to .*)(\. Path:.*)$", "$1$3");
modelState.AddModelError(key, errorMessage);
}
}
var problemDetails = problemsDetailsFactory.CreateValidationProblemDetails(actionContext.HttpContext, modelState, StatusCodes.Status400BadRequest);
return new BadRequestObjectResult(problemDetails);
};
});
那消毒:
"The JSON value could not be converted to CompanyName.Foo.Bar. Path: $ | LineNumber: 0 | BytePositionInLine: 3."
到:
"The JSON value could not be converted. Path: $ | LineNumber: 0 | BytePositionInLine: 3."
uj5u.com熱心網友回復:
讓我與您分享我們在模型系結錯誤的情況下自定義回應的實作。
首先,讓我們定義一個介面,其中包含一個可以傳遞給 的方法InvalidModelStateResponseFactory:
public interface IModelBindingErrorHandler
{
IActionResult HandleInvalidModelState(ActionContext context);
}
讓我們繼續定義兩個模型。一個用于記錄,另一個用于回應:
public class InvalidInputModel
{
public string FieldName { get; init; }
public string[] Errors { get; init; }
public override string ToString() => $"{FieldName}: {string.Join("; ", Errors)}";
}
public class GlobalErrorModel
{
public string ErrorMessage { get; init; }
public string ErrorTracingId { get; init; }
}
如您所見,它們都足夠通用,可以在其他錯誤處理程式中使用。
現在讓我們實作IModelBindingErrorHandler介面:
public class ModelBindingErrorHandler : IModelBindingErrorHandler
{
private ILogger<ModelBindingErrorHandler> logger;
public ModelBindingErrorHandler(ILogger<ModelBindingErrorHandler> logger)
=> this.logger = logger;
public IActionResult HandleInvalidModelState(ActionContext context)
{
var modelErrors = context.ModelState
.Where(stateEntry => stateEntry.Value.Errors.Any())
.Select(stateEntry => new InvalidInputModel
{
FieldName = stateEntry.Key,
Errors = stateEntry.Value.Errors.Select(error => error.ErrorMessage).ToArray()
});
var traceId = Guid.NewGuid();
logger.LogError("Invalid input model has been captured. ModelState: {modelErrors}, TraceId: {traceId}", modelErrors, traceId);
return new BadRequestObjectResult(new GlobalErrorModel
{
ErrorMessage = "Sorry, the request contains invalid data. Please revise.",
ErrorTracingId = traceId.ToString()
});
}
}
- 所以,在這里我們基本上收集了所有有價值的資訊 (
Errors) 并且我們正在記錄它們 - 我們使用一個連接日志條目和回應
traceIdGuid.NewGuid()為簡單起見,我在這里使用 a而不是correlationId
為了使這個實作的使用更容易,這里有兩種用于自注冊的擴展方法:
public static class ModelBindingErrorHandlerRegister
{
public static IServiceCollection AddModelBinderErrorHandler(this IServiceCollection services)
{
return AddModelBinderErrorHandler<ModelBindingErrorHandler>(services);
}
public static IServiceCollection AddModelBinderErrorHandler<TImpl>(this IServiceCollection services)
where TImpl : class, IModelBindingErrorHandler
{
services.AddSingleton<IModelBindingErrorHandler, TImpl>();
var serviceProvider = services.BuildServiceProvider();
var handler = serviceProvider.GetService<IModelBindingErrorHandler>();
services.Configure((ApiBehaviorOptions options) =>
options.InvalidModelStateResponseFactory = handler.HandleInvalidModelState);
return services;
}
}
- 第一種方法注冊上面的實作
- 第二種方法允許根據需要注冊自定義的
- 該
InvalidModelStateResponseFactory分配可以在里面做PostConfigure,以及
有了這些,我們就可以用一行來注冊一個自定義的模型系結處理程式:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddModelBinderErrorHandler();
...
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/331451.html
標籤:C# asp.net核心 asp.net-core-5.0
上一篇:測驗集合中是否存在數字的排列
下一篇:jwt令牌驗證失敗后授權仍在繼續
