首先,对不起我的英语。
好吧,我正在开发.Net Core Rest Api(我以前在asp.net mvc中开发过,但是第一次在net core中开发),我只是遇到了一件奇怪的事情。
该应用程序在各个层次上开发:WebApi->核心<-基础结构。
重点是,在核心层的服务中,我决定对某些业务规则进行一些例外处理。例如,有一些可翻译的实体,当您要创建新实体时,必须为应用程序中定义的每种区域性提供翻译。如果缺少翻译,我会抛出异常。
方法示例:
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发送给客户端。
四处搜寻,发现了三种主要方法: -尝试/捕捉控制器中的方法 -自定义例外过滤器 -自定义例外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 +-。
好吧,我坚信必须要有一种更快的方法,然后我尝试了另外两种方法。带有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 +-。 我仍然很坚强,这太慢了。所以我选择了最后一个选择:在动作方法中使用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 +-(我从一开始就使用中间件排除了该时间)。
老实说,对于可操作性和关注点分离,最好的方法是使用中间件,因为我不希望我的控制器知道正常流程之外的任何东西。
所以,我的问题是:
我是否对中间件做错了? 如果不是,为什么这么慢?考虑到响应时间对这个应用程序至关重要,我应该考虑哪种方法? 如果是,我该怎么更改?
感谢和问候,
答案 0 :(得分:0)
经过一些测试,我还没有找到方法来演示它,但是似乎问题出在罗伯特·佩里(Robert Perry)在评论中建议的本地计算机上的调试模式和stacktrace性能过热。
在新服务器中将Api投入生产后,中间件软件平均在15毫秒内捕获所有异常。
如果我发现本地计算机在生产模式下的响应时间为何不是最好的,我将在此处发布更多信息(也许它必须对环境变量进行某些操作,但我不确定)
无论如何,谢谢大家。
致谢