引用标准库后,异常不会转到ExceptionFilter

时间:2018-02-02 19:38:22

标签: c#

我在 .NET 4.6.1 上有一个传统的WebApi项目,其全局ExceptionFilter处理已知异常以返回带有相应状态代码的友好消息。

WebApiConfig.cs

public static void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

    config.Filters.Add(new MyExceptionFilterAttribute());
}

MyExceptionFilterAttribute.cs

internal sealed class GatewayExceptionFilterAttribute : ExceptionFilterAttribute
{
    private static readonly Dictionary<Type, HttpStatusCode> Exceptions = new Dictionary<Type, HttpStatusCode>
    {
        // HTTP 400
        [typeof(ArgumentException)] = HttpStatusCode.BadRequest,
        [typeof(ArgumentNullException)] = HttpStatusCode.BadRequest,
    };

    public override void OnException(HttpActionExecutedContext context)
    {
        var type = context.Exception.GetType();

        if (context.Exception is HttpResponseException)
            return;

        // Return 500 for unspecified errors
        var status = HttpStatusCode.InternalServerError;
        var message = Strings.ERROR_INTERNAL_ERROR;

        if (Exceptions.ContainsKey(type))
        {
            status = Exceptions[type];
            message = context.Exception.Message;
        }

        context.Response = context.Request.CreateErrorResponse(status, message);
    }
}

MyController.cs

public class MyController : ApiController
{
    public async Task<IHttpActionResult> Get()
    {
        await Task.Run(() => { throw new ArgumentNullException("Error"); });
        return Ok();
    }
}

按原样调用时,我会收到400

但是,在添加对 .NETStandard 2.0 库的引用时,异常不会转到ExceptionFilter,我收到以下错误:

{
    "message": "An error has occurred.",
    "exceptionMessage": "Method not found: 'System.Net.Http.HttpRequestMessage System.Web.Http.Filters.HttpActionExecutedContext.get_Request()'.",
    "exceptionType": "System.MissingMethodException",
    "stackTrace": "   at MyApi.Filters.MyExceptionFilterAttribute.OnException(HttpActionExecutedContext context)\r\n   at System.Web.Http.Filters.ExceptionFilterAttribute.OnExceptionAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ExceptionFilterAttribute.<ExecuteExceptionFilterAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}

感谢任何帮助。

3 个答案:

答案 0 :(得分:2)

我在使用.Net 4.6.2 Web API时遇到了同样的问题。 我在Web项目中定义了以下异常处理程序:

public class ExceptionHandlerAttribute : ExceptionFilterAttribute
{
    private readonly MyLogger _logger;

    private const string ExceptionOccuredLoggingTag = "ExceptionOccured";

    public ExceptionHandlerAttribute(MyLogger logger)
    {
        _logger = logger;
    }


    public override void OnException(HttpActionExecutedContext context)
    {
        ...
        _logger.Error(errorMessage,
            context.Exception,
            mostRecentFrame.Class.Name,
            mostRecentFrame.Method.Name,
            ExceptionOccuredLoggingTag);
        ...
    }
}

在另一个.NETStandart 2.0 dll中定义MyLogger类的位置。在尝试调用它时,它向我显示了与上述相同的异常。

这里适用的解决方法是在Web项目引用的另一个库(非.NETStandart 2.0)中定义.Net框架适配器MyLoggerAdapter(在我的示例中是业务层库): / p>

public interface ILoggerCompatable
{
    void Error(string message, object data, params string[] tags);
}

public class MyLoggerAdapter : ILoggerCompatable
{
    private readonly MyLogger _logger;

    public MyLoggerAdapter(MyLogger logger)
    {
        _logger = logger;
    }

    public void Error(string message, object data, params string[] tags) => _logger.Error(message, data, tags.Select(tag => (Tag)tag).ToArray());
}

因此,从源.NETStandart库中看不到任何内容,然后将其注入处理程序(通过Autofac):

public class ExceptionHandlerAttribute : ExceptionFilterAttribute
{
    private readonly ILoggerCompatable _logger;

    private const string ExceptionOccuredLoggingTag = "ExceptionOccured";

    public ExceptionHandlerAttribute(ILoggerCompatable logger)
    {
        _logger = logger;
    }


    public override void OnException(HttpActionExecutedContext context)
    {
        ...
        _logger.Error(errorMessage,
            context.Exception,
            mostRecentFrame.Class.Name,
            mostRecentFrame.Method.Name,
            ExceptionOccuredLoggingTag);
        ...);
    }
}

过滤器注册如下所示:

var loggerCompatable = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(ILoggerCompatable)) as ILoggerCompatable;
GlobalConfiguration.Configuration.Filters.Add(new ExceptionHandlerAttribute(loggerCompatable));

希望这有帮助!

答案 1 :(得分:1)

我也遇到了问题。

在安装.net framewokr 4.7.2运行时之后,问题已解决。

您可以在此处获取.net framewokr 4.7.2运行时: https://www.microsoft.com/net/download

PS:此问题发生在未安装.net framewokr 4.7.x的Windows 7和Windows Server 2008 R2上, 并且默认情况下不会出现在具有.net framewokr 4.7.x的Windows 10上。

答案 2 :(得分:0)

对不起,我还没有发布答案。因此,我们发现将标准项目添加到.NET Framework项目时某些API不兼容。另一个示例是访问控制器中的User。将Standard项目添加到.NET Framework ASP.NET项目后,您将无法在运行时访问此项目(甚至可能引发异常)。

出于100%的兼容性,我们最终以Standard编写了新库,同时以.NET 4.6、4.6.1和4.6.2为目标,因为我们的项目仍在这些库下运行。我们将这些程序包上传到nuget提要,该提要允许其他应用程序引用正确的二进制文件。

希望这会有所帮助!