我正在使用 .Net Core 2.2
制作 .net Core WebApi。 API 已准备就绪,但失败消息和响应是我陷入困境的地方。
现在,我得到了如下的回复
json
{
"empId":1999,
"empName":"Conroy, Deborah",
"enrollmentStatus":true,
"primaryFingerprintScore":65,
"secondaryFingerprintScore":60,
"primaryFingerprint":null,
"secondaryFingerprint":null,
"primaryFingerprintType":null,
"secondaryFingerprintType":null}
}
我创建了一个 json 格式化程序类并编写了以下代码
public class SuperJsonOutputFormatter : JsonOutputFormatter
{
public SuperJsonOutputFormatter(
JsonSerializerSettings serializerSettings,
ArrayPool<char> charPool) : base(serializerSettings, charPool)
{
}
public override async Task WriteResponseBodyAsync(
OutputFormatterWriteContext context,
Encoding selectedEncoding)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (selectedEncoding == null)
throw new ArgumentNullException(nameof(selectedEncoding));
using (TextWriter writer =
context.WriterFactory(
context.HttpContext.Response.Body,
selectedEncoding))
{
var rewrittenValue = new
{
resultCode = context.HttpContext.Response.StatusCode,
resultMessage =
((HttpStatusCode)context.HttpContext.Response.StatusCode)
.ToString(),
result = context.Object
};
this.WriteObject(writer, rewrittenValue);
await writer.FlushAsync();
}
}
我希望所有错误代码都作为通用错误消息发送,如下面的 JSON。
状态正常:
{
"status" : True,
"error" : null,
"data" : {
{
"empId":1999,
"empName":"Conroy, Deborah",
"enrollmentStatus":true,
"primaryFingerprintScore":65,
"secondaryFingerprintScore":60,
"primaryFingerprint":null,
"secondaryFingerprint":null,
"primaryFingerprintType":null,
"secondaryFingerprintType":null}
}
}
}
对于 404、500、400、204 等其他状态
{
"status" : False,
"error" : {
"error code" : 404,
"error description" : Not Found
},
"data" : null
}
最佳答案
I expect all the error codes to be sent as generic error messages like the JSON below
你就快到了。您需要做的是启用 SuperJsonOutputFormatter。
对格式化程序进行一点更改
首先,您的格式化程序没有返回具有与您想要的相同架构的 json。因此,我创建一个虚拟类来保存错误代码
和错误描述
的信息:
public class ErrorDescription{ public ErrorDescription(HttpStatusCode statusCode) { this.Code = (int)statusCode; this.Description = statusCode.ToString(); } [JsonProperty("error code")] public int Code {get;set;} [JsonProperty("error description")] public string Description {get;set;} }
And change your WriteResponseBodyAsync() method as below:
... using (TextWriter writer = context.WriterFactory(context.HttpContext.Response.Body, selectedEncoding)) { var statusCode = context.HttpContext.Response.StatusCode; var rewrittenValue = new { status = IsSucceeded(statusCode), error = IsSucceeded(statusCode) ? null : new ErrorDescription((HttpStatusCode)statusCode), data = context.Object, }; this.WriteObject(writer, rewrittenValue); await writer.FlushAsync(); }
Here the IsSucceeded(statusCode)
is a simple helper method that you can custom as you need:
private bool IsSucceeded(int statusCode){
// I don't think 204 indicates that's an error.
// However, you could comment out it if you like
if(statusCode >= 400 /* || statusCode==204 */ ) { return false; }
return true;
}
启用格式化程序
其次,要启用自定义格式化程序,您有两种方法:一种方法是将其注册为全局格式化程序,另一种方法是为特定 Controller 或操作启用它。就我个人而言,我认为第二种方式更好。因此,我创建了一个操作过滤器来启用您的格式化程序。
这是动态启用自定义格式化程序的过滤器的实现:
public class SuperJsonOutputFormatterFilter : IAsyncActionFilter{
private readonly SuperJsonOutputFormatter _formatter;
// inject your SuperJsonOutputFormatter service
public SuperJsonOutputFormatterFilter(SuperJsonOutputFormatter formatter){
this._formatter = formatter;
}
// a helper method that provides an ObjectResult wrapper over the raw object
private ObjectResult WrapObjectResult(ActionExecutedContext context, object obj){
var wrapper = new ObjectResult(obj);
wrapper.Formatters.Add(this._formatter);
context.Result= wrapper;
return wrapper;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
ActionExecutedContext resultContext = await next();
// in case we get a 500
if(resultContext.Exception != null && ! resultContext.ExceptionHandled){
var ewrapper = this.WrapObjectResult(resultContext, new {});
ewrapper.StatusCode = (int) HttpStatusCode.InternalServerError;
resultContext.ExceptionHandled = true;
return;
}
else {
switch(resultContext.Result){
case BadRequestObjectResult b : // 400 with an object
var bwrapper=this.WrapObjectResult(resultContext,b.Value);
bwrapper.StatusCode = b.StatusCode;
break;
case NotFoundObjectResult n : // 404 with an object
var nwrapper=this.WrapObjectResult(resultContext,n.Value);
nwrapper.StatusCode = n.StatusCode;
break;
case ObjectResult o : // plain object
this.WrapObjectResult(resultContext,o.Value);
break;
case JsonResult j : // plain json
this.WrapObjectResult(resultContext,j.Value);
break;
case StatusCodeResult s: // other statusCodeResult(including NotFound,NoContent,...), you might want to custom this case
var swrapper = this.WrapObjectResult(resultContext, new {});
swrapper.StatusCode = s.StatusCode;
break;
}
}
}
}
并且不要忘记将格式化程序注册为服务:
services.AddScoped<SuperJsonOutputFormatter>();
最后,当您想要启用格式化程序时,只需为 Controller 或操作添加 [TypeFilter(typeof(SuperJsonOutputFormatterFilter))]
注释即可。
演示
让我们为测试创建一个操作方法:
[TypeFilter(typeof(SuperJsonOutputFormatterFilter))]
public IActionResult Test(int status)
{
// test json result(200)
if(status == 200){ return Json(new { Id = 1, }); }
// test 400 object result
else if(status == 400){ return BadRequest( new {}); }
// test 404 object result
else if(status == 404){ return NotFound(new { Id = 1, }); }
// test exception
else if(status == 500){ throw new Exception("unexpected exception"); }
// test status code result
else if(status == 204){ return new StatusCodeResult(204); }
// test normal object result(200)
var raw = new ObjectResult(new XModel{
empId=1999,
empName = "Conroy, Deborah",
enrollmentStatus=true,
primaryFingerprintScore=65,
secondaryFingerprintScore=60,
primaryFingerprint = null,
secondaryFingerprint= null,
primaryFingerprintType=null,
secondaryFingerprintType=null
});
return raw;
}
屏幕截图:
关于asp.net-core - 在 .net core web api 中发送自定义错误响应的最佳方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57869900/