在异常过滤器中捕获来自服务的错误
Catching errors from services in Exception Filter
我创建了一个在我的 aspnet 项目中使用的服务,该服务检索和验证 header 等。问题是异常过滤器无法捕获服务抛出的错误,因为它不在异常过滤器的范围内,因此给用户一个丑陋的内部服务器错误。有什么方法可以优雅地 return 向使用服务的用户描述参数错误?
初创公司:
services.AddScoped<UserService>();
services
.AddMvc(x =>
{
x.Filters.Add(typeof(Filters.MyExceptionFilter));
})
异常过滤器:
public class MyExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (context.Exception is ArgumentException argumentException)
{
var response = context.HttpContext.Response;
context.ExceptionHandled = true;
response.StatusCode = 400;
context.Result = new ObjectResult(argumentException.Message);
return;
}
}
}
服务:
public class UserService
{
public readonly string UserId;
public UserService(IHttpContextAccessor context)
{
if (!context.HttpContext.Request.Headers.TryGetValue("x-test", out var user))
{
throw new ArgumentException($"x-test header is required.");
}
UserId = user;
//do other stuff
}
}
控制器操作方法:
public async Task<IActionResult> Delete(string id,
[FromServices] UserService userService)
{
//do stuff
}
C# 中的一个经验法则是在构造函数中做的工作越少越好。这有几个很好的理由(例如,您不能处理在其构造函数中引发异常的 class )。另一个很好的理由是,正如您所发现的,构造可能发生在与您实际使用 class.
的地方不同的地方(例如 DI 容器)。
修复应该非常简单 - 只需将逻辑移出构造函数即可。您可以使用 Lazy<T>
来执行此操作,例如:
public class UserService
{
public readonly Lazy<string> _userId ;
public UserService(IHttpContextAccessor context)
{
_userId = new Lazy<string>(() =>
{
if (!context.HttpContext.Request.Headers.TryGetValue("x-test", out var user))
{
throw new ArgumentException($"x-test header is required.");
}
return user;
});
//do other stuff
}
public string UserId => _userId.Value;
}
或者您可以在需要时获取值:
public class UserService
{
public readonly IHttpContextAccessor _context;
public UserService(IHttpContextAccessor context)
{
_context = context;
//do other stuff
}
public string UserId
{
get
{
if (_context.HttpContext.Request.Headers.TryGetValue("x-test", out var user))
{
return user;
}
else
{
throw new ArgumentException($"x-test header is required.");
}
}
}
}
我创建了一个在我的 aspnet 项目中使用的服务,该服务检索和验证 header 等。问题是异常过滤器无法捕获服务抛出的错误,因为它不在异常过滤器的范围内,因此给用户一个丑陋的内部服务器错误。有什么方法可以优雅地 return 向使用服务的用户描述参数错误?
初创公司:
services.AddScoped<UserService>();
services
.AddMvc(x =>
{
x.Filters.Add(typeof(Filters.MyExceptionFilter));
})
异常过滤器:
public class MyExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (context.Exception is ArgumentException argumentException)
{
var response = context.HttpContext.Response;
context.ExceptionHandled = true;
response.StatusCode = 400;
context.Result = new ObjectResult(argumentException.Message);
return;
}
}
}
服务:
public class UserService
{
public readonly string UserId;
public UserService(IHttpContextAccessor context)
{
if (!context.HttpContext.Request.Headers.TryGetValue("x-test", out var user))
{
throw new ArgumentException($"x-test header is required.");
}
UserId = user;
//do other stuff
}
}
控制器操作方法:
public async Task<IActionResult> Delete(string id,
[FromServices] UserService userService)
{
//do stuff
}
C# 中的一个经验法则是在构造函数中做的工作越少越好。这有几个很好的理由(例如,您不能处理在其构造函数中引发异常的 class )。另一个很好的理由是,正如您所发现的,构造可能发生在与您实际使用 class.
的地方不同的地方(例如 DI 容器)。修复应该非常简单 - 只需将逻辑移出构造函数即可。您可以使用 Lazy<T>
来执行此操作,例如:
public class UserService
{
public readonly Lazy<string> _userId ;
public UserService(IHttpContextAccessor context)
{
_userId = new Lazy<string>(() =>
{
if (!context.HttpContext.Request.Headers.TryGetValue("x-test", out var user))
{
throw new ArgumentException($"x-test header is required.");
}
return user;
});
//do other stuff
}
public string UserId => _userId.Value;
}
或者您可以在需要时获取值:
public class UserService
{
public readonly IHttpContextAccessor _context;
public UserService(IHttpContextAccessor context)
{
_context = context;
//do other stuff
}
public string UserId
{
get
{
if (_context.HttpContext.Request.Headers.TryGetValue("x-test", out var user))
{
return user;
}
else
{
throw new ArgumentException($"x-test header is required.");
}
}
}
}