C# 正在调用ExceptionHandler但未返回JSON

C# 正在调用ExceptionHandler但未返回JSON,c#,asp.net-web-api,C#,Asp.net Web Api,我有一个用于Web API的自定义异常处理程序: public class GlobalExceptionHandler : ExceptionHandler { private class ErrorInformation { public string Message { get; set; } public DateTime ErrorDate { get; set; } } public override void Han

我有一个用于Web API的自定义
异常处理程序

public class GlobalExceptionHandler : ExceptionHandler
{
    private class ErrorInformation
    {
        public string Message { get; set; }
        public DateTime ErrorDate { get; set; }
    }

    public override void Handle(ExceptionHandlerContext context)
    {
        context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.InternalServerError,
            new ErrorInformation { Message = "We apologize but an unexpected error occurred. Please try again later.", ErrorDate = DateTime.UtcNow }));
    }
}
这是控制器代码

[HttpPost]
public async Task<HttpResponseMessage> UserNameChange(UserNameChangeRequest updateUsersRequest)
{
    throw new Exception("sdfsdf");
}
如果我设置一个断点,它会被很好地命中。但是客户端的输出仍然是HTML,而不是预期的JSON

更新: 我添加了以下内容作为过滤器属性,结果仍然相同。没有JSON,只有HTML错误页面 公共类CustomExceptionFilterAttribute:ExceptionFilterAttribute { public override void OneException(HttpActionExecuteContext ActionExecuteContext) {

        var exceptionMessage = actionExecutedContext.Exception.InnerException?.Message ?? actionExecutedContext.Exception.Message;


        var response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.InternalServerError, new { Message = exceptionMessage });

        actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.OK, new {ErrorMessage = actionExecutedContext.Exception.Message},
            new JsonMediaTypeFormatter());


    }
}
我创建了一个新项目,添加了我的NewtonSoft JSON配置和一个客户ErrorAtribute,工作正常


在我的项目中,有什么可以阻止错误以JSON的形式出现?即使我在浏览器中导航到API端点时,它显示为一般HTML错误,但在示例项目中,它显示的代码与我想要的JSON消息相同???

您是否尝试将
MediaTypeFormatter
设置为JSON

    context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.InternalServerError,
                new ErrorInformation { Message = "We apologize but an unexpected error occurred. Please try again later.", ErrorDate = DateTime.UtcNow }, 
                JsonMediaTypeFormatter.DefaultMediaType));

下面是我安装的软件包

<packages>
  <package id="Microsoft.AspNet.Cors" version="5.2.3" targetFramework="net462" />
  <package id="Microsoft.AspNet.WebApi" version="5.2.2" targetFramework="net462" />
  <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net462" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net462" />
  <package id="Microsoft.AspNet.WebApi.Cors" version="5.2.3" targetFramework="net462" />
  <package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.2" targetFramework="net462" />
  <package id="Newtonsoft.Json" version="6.0.4" targetFramework="net462" />
</packages>
下面是处理方法

public override void Handle(ExceptionHandlerContext context)
{
   string errorMessage = "An unexpected error occured";
     var response = context.Request.CreateResponse(HttpStatusCode.InternalServerError,
                    new ErrorInformation() 
                    {
                        Message = "We apologize but an unexpected error occured. Please try again later.",
                        ErrorDate = DateTime.UtcNow 
                    }
                  );
   response.Headers.Add("X-Error", errorMessage);
   context.Result = new ResponseMessageResult(response); 
}
输出


我想你漏掉了以下几行:

json.UseDataContractJsonSerializer = true;
添加该行后,它应该为您正确地序列化为JSON。如果没有序列化程序,您可以设置格式化程序,但实际上它不会做任何事情

根据代码,您似乎没有使用默认的
Newtonsoft.Json
设置,而是为数据契约序列化程序而设计的

注意:只有当您不想使用
Newtonsoft.Json
作为默认序列化程序时,此答案才有用。

请改用,例如:

namespace Microsoft.UPP.Calc.WebApi.Logging
{
    public sealed class AiExceptionLogger : ExceptionLogger
    {
        private readonly ITelemetryClient _telemetryClient;

        public AiExceptionLogger(ITelemetryClient telemetryClient)
        {
            _telemetryClient = telemetryClient;
        }

        public override void Log(ExceptionLoggerContext context)
        {
            LogException(context.Exception);
        }

        public void LogException(Exception exception)
        {
            var properties = Enumerable.Zip(exception.Data.Keys.Cast<string>(),
                                            exception.Data.Values.OfType<string>(),
                                            (k, v) => new { Key = k, Value = v })
                                       .Where(x => x.Value != null)
                                       .ToDictionary(x => x.Key, x => x.Value);
            _telemetryClient.TrackException(exception, properties);
        }

        public void LogEvent(string eventName, IDictionary<string, string> properties)
        {
            _telemetryClient.TrackEvent(eventName, properties);
        }
    }
}
namespace Microsoft.UPP.Calc.WebApi.Logging
{
公共密封类AiExceptionLogger:ExceptionLogger
{
专用只读ITelemetryClient\u遥测客户端;
公共AiExceptionLogger(ITelemetryClient遥测客户端)
{
_遥测客户端=遥测客户端;
}
公共重写无效日志(例外LoggerContext上下文)
{
LogException(context.Exception);
}
公共无效日志异常(异常)
{
var properties=Enumerable.Zip(exception.Data.Keys.Cast(),
类型()的异常.Data.Values.of,
(k,v)=>new{Key=k,Value=v})
.Where(x=>x.Value!=null)
.ToDictionary(x=>x.Key,x=>x.Value);
_telemetryClient.TrackException(异常,属性);
}
public void LogEvent(字符串eventName,IDictionary属性)
{
_telemetryClient.TrackEvent(事件名称、属性);
}
}
}

这是一篇很好的文章,概述了实现这一点的一种方法。我过去使用过这种技术,效果很好。搜索
textplanerrorresult

若要确定应用程序是否使用自定义http错误,请在IIS中打开应用程序下的“自定义错误”部分,或在web.config中查找httpErrors部分。此构造已存在一段时间。如果您使用的是旧版应用程序,请在web.config中查找以下部分:

<httpErrors errorMode="Custom" existingResponse="Auto" defaultResponseMode="ExecuteURL">
  <clear />
  <error statusCode="404" path="/errors/404.aspx" responseMode="ExecuteURL" />
  <error statusCode="500" path="/errors/500.aspx" responseMode="ExecuteURL" />
  <error statusCode="400" path="/errors/400.aspx" responseMode="ExecuteURL" />
</httpErrors>

所以,原来罪魁祸首是一个名为“SerilogWeb.Classic.WebApi”的NuGet包

我不确定这个所谓的“包”到底在做什么,但似乎正在拦截我的WebApi例外过滤器


花了一整天的时间来解决这个问题,所以,我希望这能帮助下一个人解决这样的问题。

将应用程序池中的IIS设置为使用集成模式

什么是响应?您是否从浏览器中检查过?响应是HTML。sdfsdfI希望响应是我希望返回的JSON。为什么它会返回JSON,您没有序列化或明确表示返回JSON。您需要类似于这些内容的内容。这对我来说没有任何帮助problem@PranayI 一定是做错了什么,没有任何代码组合可以让它起作用。我还注释掉了其他所有筛选器属性。@JCircio您有
Newtonsoft.Json
Nuget-package吗?@JCircio-您能复制并通过我的代码,然后进行一个try@Greg-是的……我补充道that@PranayRana我知道你这么做了,它很管用。如果JCircio没有,那么Web Api就没有了ldn不能序列化,因为Json.Net是它所依赖的默认值。您必须指定使用内置的.Net。我添加了它(见上文)不走运。这里也不走运。是的,我可以捕捉到错误,但我想做的是将JSON返回到客户端。出于某种原因,我的项目没有这样做。我的测试项目具有确切的筛选器属性。您是否在IIS中使用自定义错误进行重写,在这种情况下,您需要在管道中的某个位置指定响应。TrySkipIisCustomErrors。不是吗我知道。但是这是一个很多年前开始的大项目。我在哪里可以找到这个?好,我看了这一点,我们没有做任何类似的事情。但是它确实有意义,因为不管我做什么,我都不会得到JSON,但是通用HTML错误PGEI添加了配置部分来检查。你可以考虑把这个标记为答案,即使它是。您自己的,因为帮助了其他偶然发现bit的人。供将来参考:此PR现在应在SerilogWeb.Classic.WebApi v4.0.5中修复此问题:
namespace Microsoft.UPP.Calc.WebApi.Logging
{
    public sealed class AiExceptionLogger : ExceptionLogger
    {
        private readonly ITelemetryClient _telemetryClient;

        public AiExceptionLogger(ITelemetryClient telemetryClient)
        {
            _telemetryClient = telemetryClient;
        }

        public override void Log(ExceptionLoggerContext context)
        {
            LogException(context.Exception);
        }

        public void LogException(Exception exception)
        {
            var properties = Enumerable.Zip(exception.Data.Keys.Cast<string>(),
                                            exception.Data.Values.OfType<string>(),
                                            (k, v) => new { Key = k, Value = v })
                                       .Where(x => x.Value != null)
                                       .ToDictionary(x => x.Key, x => x.Value);
            _telemetryClient.TrackException(exception, properties);
        }

        public void LogEvent(string eventName, IDictionary<string, string> properties)
        {
            _telemetryClient.TrackEvent(eventName, properties);
        }
    }
}
<httpErrors errorMode="Custom" existingResponse="Auto" defaultResponseMode="ExecuteURL">
  <clear />
  <error statusCode="404" path="/errors/404.aspx" responseMode="ExecuteURL" />
  <error statusCode="500" path="/errors/500.aspx" responseMode="ExecuteURL" />
  <error statusCode="400" path="/errors/400.aspx" responseMode="ExecuteURL" />
</httpErrors>