我使用Owin Self-hosting和WebApi编写了简单的服务器:
namespace OwinSelfHostingTest
{
using System.Threading;
using System.Web.Http;
using Microsoft.Owin.Hosting;
using Owin;
public class Startup
{
public void Configuration(IAppBuilder builder)
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
"Default",
"{controller}/{id}",
new { id = RouteParameter.Optional }
);
builder.UseWebApi(config);
}
}
public class Server
{
private ManualResetEvent resetEvent = new ManualResetEvent(false);
private Thread thread;
private const string ADDRESS = "http://localhost:9000/";
public void Start()
{
this.thread = new Thread(() =>
{
using (var host = WebApp.Start<Startup>(ADDRESS))
{
resetEvent.WaitOne(Timeout.Infinite, true);
}
});
thread.Start();
}
public void Stop()
{
resetEvent.Set();
}
}
}
当控制器中出现异常时,Owin会返回如下的XML响应:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>Attempted to divide by zero.</ExceptionMessage>
<ExceptionType>System.DivideByZeroException</ExceptionType>
<StackTrace>
...
</StackTrace>
</Error>
但我想要不同的输出 - 所以我怎么能覆盖它?
答案 0 :(得分:9)
您可以通过创建OWIN MiddleWare并将其挂钩到管道中来实现:
public class CustomExceptionMiddleware : OwinMiddleware
{
public CustomExceptionMiddleware(OwinMiddleware next) : base(next)
{}
public override async Task Invoke(IOwinContext context)
{
try
{
await Next.Invoke(context);
}
catch(Exception ex)
{
// Custom stuff here
}
}
}
并在启动时挂钩:
public class Startup
{
public void Configuration(IAppBuilder builder)
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
"Default",
"{controller}/{id}",
new { id = RouteParameter.Optional }
);
builder.Use<CustomExceptionMiddleware>().UseWebApi(config);
}
}
这样,您的中间件将捕获任何未处理的异常,并允许您自定义输出结果。
需要注意的重要事项:如果托管的东西有自己的异常处理逻辑,就像WebAPI那样,异常不会传播。此处理程序适用于由托管的基础服务取消隐藏的任何异常。
答案 1 :(得分:3)
当您等待异步方法时,异常不会被抛入调用者的上下文中,但可以通过检查返回给调用者的任务来获取异常。
因此,通过对@ yuval-itzchakov提供的解决方案的这种修改,您将能够捕获潜在的异常:
var subtask = Next.Invoke(context);
await subtask;
if (subtask.Exception != null)
{
// log subtask.Exception here
}