[英]Net Core - Why exception middleware is so slow?
首先,抱歉我的英语。
好吧,我正在开发一个.Net Core Rest Api(我之前在asp.net mvc中开发过,但在net core中是第一次开发)我只是面对一个奇怪的事情。
该应用程序以各种层次开发:WebApi - > Core < - Infrastructure。
关键是在核心层的服务中,我决定对某些业务规则进行一些例外处理。 例如,有一些可翻译实体,当您要创建新实体时,必须为应用程序中定义的每种文化提供翻译。 如果缺少翻译,我会抛出异常。
方法示例:
public async Task<CompanyResource> Add(CompanyResource companyResource)
{
var cultures = await _cultureRepository.GetAllAsync();
if (cultures.Any(culture => companyResource.Translations.All(t => t.CultureCode != culture.Code)))
throw new MissingTranslationsException();
await _companyResourceRepository.AddAsync(companyResource);
return companyResource;
}
现在我想知道如何处理控制器中的异常,以根据每种异常类型和人类可读消息向客户端发送正确的httpStatusCode。
搜索我发现了3种主要方法: - 在控制器中的方法中尝试/捕获 - 自定义异常过滤器 - 自定义异常中间件
我决定使用midleware,因为它似乎是最好的方法,在所有应用程序中都有一个中心位置来处理异常并将消息发送给客户端,所以我做了这个实现:
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlingMiddleware(RequestDelegate next)
{
this._next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var code = HttpStatusCode.InternalServerError;
if (exception is InvalidPermissionsException) code = HttpStatusCode.Forbidden;
else if (exception is DuplicateEntityException) code = HttpStatusCode.Conflict;
else if (exception is MissingTranslationsException) code = HttpStatusCode.BadRequest;
else if (exception is ApplicationException) code = HttpStatusCode.BadRequest;
var result = JsonConvert.SerializeObject(new []{ exception.Message });
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)code;
await context.Response.WriteAsync(result);
}
}
然后我将中间件连接到管道:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//...other code
app.UseMiddleware<ErrorHandlingMiddleware>();
app.UseHttpsRedirection();
app.UseMvc();
}
好吧,在这一点上,所有工作都很完美,buuuuuut,我只是注意到,当中间件处理异常时,响应时间远远不能确定。
这是使用中间件时的响应时间:
经过多次测试,平均响应时间为460ms + - 。
好吧,我坚持认为必须有更快的方法,然后我尝试了其他2种方法。 使用exceptionFilter属性:
public class HandleExceptionAttribute : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
var code = HttpStatusCode.InternalServerError;
var exception = context.Exception;
if (exception is InvalidPermissionsException) code = HttpStatusCode.Forbidden;
else if (exception is DuplicateEntityException) code = HttpStatusCode.Conflict;
else if (exception is MissingTranslationsException) code = HttpStatusCode.BadRequest;
else if (exception is ApplicationException) code = HttpStatusCode.BadRequest;
context.HttpContext.Response.StatusCode = (int)code;
context.Result = new JsonResult(new[] { exception.Message });
}
}
使用滤波器时,响应时间降至250ms + - 平均值。 我仍然很难,这太慢了..所以我选择了最后一个选项:在action方法中使用try catch:
[HttpPost]
public async Task<IActionResult> Post([FromBody] CompanyResourceDto companyResourceDto)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
var companyresource = _mapper.Map<CompanyResource>(companyResourceDto);
try
{
companyresource = await _resourcesService.Add(companyresource);
}
catch (Exception e)
{
return BadRequest(new[] {e.Message});
}
return CreatedAtRoute("Getresource", new { id = companyresource.Id }, _mapper.Map<CompanyResourceDto>(companyresource));
}
而且,地狱,异常情况下的平均响应时间下降到85ms + - (我从开头就用中间件除外)。
老实说,我认为最好的用于管理和分离关注点是使用中间件,因为我不希望我的控制器能够从正常流程中了解任何东西。
所以,我的问题是:
我是否对中间件做错了什么? 如果没有,为什么这么慢,我应该考虑到这个应用程序的响应时间至关重要? 如果是的话,我应该改变什么?
谢谢并恭祝安康,
经过一些测试,我还没有找到演示它的方法,但似乎问题是关于本地机器中的调试模式和堆栈跟踪性能过热,正如Robert Perry在评论中所建议的那样。
在新服务器中设置生产中的Api之后,中间件在平均15ms + - 的时间内捕获所有异常。
如果我发现为什么本地机器中生产模式的响应时间不是最好的(也许它必须对环境变量做一些但我不确定),我会在这里发布更多信息
无论如何,谢谢大家。
问候
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.