C# 如何在EmbedIO Web API中设置异常处理程序

C# 如何在EmbedIO Web API中设置异常处理程序,c#,embedio,C#,Embedio,我正在使用WebAPI模块 我希望有一个异常处理程序,它将捕获所有未处理的异常,并根据异常类型返回合适的HTTP错误代码。然而,这是否能够实现还不清楚 该类公开了一个名为OnUnhandledException的属性,该属性可以设置为ExceptionHandlerCallback,但在调用回调时,响应的状态代码已设置为HttpStatusCode.InternalServerError,如中所述 这不方便,因为我想自己设置响应代码 WebModuleBase公开一个名为OnHttpExcept

我正在使用WebAPI模块

我希望有一个异常处理程序,它将捕获所有未处理的异常,并根据异常类型返回合适的HTTP错误代码。然而,这是否能够实现还不清楚

该类公开了一个名为OnUnhandledException的属性,该属性可以设置为ExceptionHandlerCallback,但在调用回调时,响应的状态代码已设置为HttpStatusCode.InternalServerError,如中所述

这不方便,因为我想自己设置响应代码

WebModuleBase公开一个名为OnHttpException的不同属性,该属性可以设置为。这可以设置为 DataResponse(ResponseSerializer.Json)部分解决了这个问题

现在主要的问题是应用程序异常必须在控制器中转换为HttpException

我想从域代码中抛出自定义异常,将它们放入异常处理程序中,然后根据初始异常返回一个HTTPException

基本上类似于ASP.NET Web API中的内容

以下是设置web服务器的代码:

var webApiModule = new WebApiModule("/api", ResponseSerializer.Json)
    .WithController<MyController>();
webApiModule.OnUnhandledException = ExceptionHandler.DataResponseForException();
webApiModule.OnHttpException = ExceptionHandler.DataResponseForHttpException();

WebServerEmbedded = new EmbedIO.WebServer(
    opt => opt
        .WithUrlPrefix(url)
        .WithMode(HttpListenerMode.EmbedIO))
        .WithModule(null, webApiModule);

谢谢。

异常以及HTTP异常都由EmbedIO在模块和服务器级别处理(每个嵌套模块组引入了一个更高的级别,但这超出了重点)

HTTP异常的
catch
子句总是位于“通用”的
catch
子句之前,原因很明显,HTTP异常本身就是异常,需要进行分类。因此,如果异常处理程序抛出HTTP异常,则后者必须在外部级别处理

换句话说,您可以编写一个抛出HTTP异常的模块级异常处理程序,然后使用服务器级HTTP异常处理程序生成适当的响应

var webApiModule = new WebApiModule("/api", ResponseSerializer.Json)
    .WithController<MyController>()
    .HandleUnhandledException(ExceptionHandler.DataResponseForException));

WebServerEmbedded = new EmbedIO.WebServer(
    opt => opt
        .WithUrlPrefix(url)
        .WithMode(HttpListenerMode.EmbedIO))
    .WithModule(webApiModule)
    .HandleHttpException(ExceptionHandler.DataResponseForHttpException);

编辑:如果您需要自定义异常,有一种更简单的方法:只需实现您的异常

您可以看到HTTP异常处理代码如何使用
IHTTPEException
方法

可能是最模糊的方法,
PrepareResponse
的一个例子


编辑:我在
DataResponseForHttpException

中添加了设置状态代码的功能。是否要使用自定义异常,比如说InvalidOperationException,然后抛出它并将其转换为HTTPException?是的,完全正确。例如,假设我的存储库层正在抛出一个名为EntityNotFoundException的自定义异常。我希望能够在web项目中的异常处理程序中捕获此问题,并基于此抛出HttpNotFound。您能否将此问题发布到我找到了一个解决方法,我将很快发布此修复程序。您可以查看PR:谢谢您的回答。我尝试了你建议的第一种方法,但代码总是500。请参见问题描述的开头:“WebModuleBase类公开了一个名为OnUnhandledException的属性,该属性可以设置为ExceptionHandlerCallback,但在调用回调时,响应的状态代码已经设置为HttpStatusCode.InternalServerError,如代码注释中所述。”至于第二个建议,我不能让与HTTP无关的异常类实现IHTTPEException。还是我误解了你的建议?@Paul响应的状态代码已经设置好了,但是可以由exceptiopn处理程序重新设置,因为在调用客户端时还没有将头发送到客户端。当然,您可以拥有自己的异常类,并且它们没有义务实现
IHTTPEException
。我只是建议,如果您关心的异常都是您自己的(即您的应用程序的一部分),让它们实现
IHTTPEException
是一种快速的方法,可以为每个异常提供自己的响应代码,以及它们自己的消息,甚至自定义头(如果需要)。此外,如果您的响应代码取决于异常的类型,那么让每个响应代码直接由异常设置—而不是在异常处理程序中的
开关
语句(或一系列
catch
子句)中设置—将使代码更干净。
var webApiModule = new WebApiModule("/api", ResponseSerializer.Json)
    .WithController<MyController>()
    .HandleUnhandledException(ExceptionHandler.DataResponseForException));

WebServerEmbedded = new EmbedIO.WebServer(
    opt => opt
        .WithUrlPrefix(url)
        .WithMode(HttpListenerMode.EmbedIO))
    .WithModule(webApiModule)
    .HandleHttpException(ExceptionHandler.DataResponseForHttpException);
internal static class ExceptionHandler
{
    public static Task DataResponseForException(IHttpContext context, Exception exception)
    {
        // Replace ANY_VALID_STATUS CODE with, well, any valid status code.
        // Of course you can use different status codes according to, for example,
        // the type of exception.
        throw new HttpException(ANY_VALID_STATUS_CODE, exception.Message);
    }

    public static Task DataResponseForHttpException(IHttpContext context, IHttpException httpException)
    {
        context.Response.StatusCode = (int)HttpStatusCode.OK;
        return ResponseSerializer.Json(context, httpException.Message);
    }
}