简体   繁体   English

错误处理(将ex.Message发送到客户端)

[英]Error handling (Sending ex.Message to the client)

I have an ASP.NET Core 1.0 Web API application and trying to figure out how to pass the exception message to the client if a function that my controller is calling errors out. 我有一个ASP.NET Core 1.0 Web API应用程序,并尝试弄清楚如果我的控制器调用的函数错误输出异常消息到客户端。

I have tried so many things, but nothing implements IActionResult . 我尝试了很多东西,但没有实现IActionResult

I don't understand why this isn't a common thing that people need. 我不明白为什么这不是人们需要的常见事情。 If there truthfully is no solution can someone tell me why? 如果真的没有解决方案可以有人告诉我为什么?

I do see some documentation out there using HttpResponseException(HttpResponseMessage) , but in order to use this, I have to install the compat shim. 我确实使用HttpResponseException(HttpResponseMessage)看到了一些文档,但为了使用它,我必须安装compat shim。 Is there a new way of doing these things in Core 1.0? 在Core 1.0中有没有新的方法来做这些事情?

Here is something I have been trying with the shim but it isn't working: 这是我一直在尝试使用垫片,但它不起作用:

// GET: api/customers/{id}
[HttpGet("{id}", Name = "GetCustomer")]
public IActionResult GetById(int id)
{
    Customer c = _customersService.GetCustomerById(id);
    if (c == null)
    {
        var response = new HttpResponseMessage(HttpStatusCode.NotFound)
        {
            Content = new StringContent("Customer doesn't exist", System.Text.Encoding.UTF8, "text/plain"),
            StatusCode = HttpStatusCode.NotFound

        };

        throw new HttpResponseException(response);

        //return NotFound();
    }
    return new ObjectResult(c);
}

When the HttpResponseException is thrown, I look on the client and can't find the message I am sending anything in the content. 抛出HttpResponseException ,我查看客户端,无法找到我在内容中发送任何内容的消息。

Here is an simple error DTO class 这是一个简单的错误DTO类

public class ErrorDto
{
    public int Code {get;set;}
    public string Message { get; set; }

    // other fields

    public override string ToString()
    {
        return JsonConvert.SerializeObject(this);
    }
}

And then using the ExceptionHandler middleware: 然后使用ExceptionHandler中间件:

            app.UseExceptionHandler(errorApp =>
            {
                errorApp.Run(async context =>
                {
                    context.Response.StatusCode = 500; // or another Status accordingly to Exception Type
                    context.Response.ContentType = "application/json";

                    var error = context.Features.Get<IExceptionHandlerFeature>();
                    if (error != null)
                    {
                        var ex = error.Error;

                        await context.Response.WriteAsync(new ErrorDto()
                        {
                            Code = <your custom code based on Exception Type>,
                            Message = ex.Message // or your custom message
                            // other custom data
                        }.ToString(), Encoding.UTF8);
                    }
                });
            });

Yes it is possible to change the status code to whatever you need: 是的,可以将状态代码更改为您需要的任何内容:

In your CustomExceptionFilterAttribute.cs file modify the code as follows: 在CustomExceptionFilterAttribute.cs文件中,修改代码如下:

public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        var exception = context.Exception;
        context.Result = new ContentResult
        {
            Content = $"Error: {exception.Message}",
            ContentType = "text/plain",
            // change to whatever status code you want to send out
            StatusCode = (int?)HttpStatusCode.BadRequest 
        };
    }
}

That's pretty much it. 这就是它。

If you have custom exceptions, then you can also check for them when grabbing the thrown exception from the context. 如果您有自定义异常,那么您也可以在从上下文中获取抛出的异常时检查它们。 Following on from that you can then send out different HTTP Status Codes depdending on what has happened in your code. 接下来,您可以发送不同的HTTP状态代码,代替代码中发生的事情。

Hope that helps. 希望有所帮助。

You can create a custom Exception Filter like below 您可以创建一个自定义的异常过滤器,如下所示

public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        var exception = context.Exception;
        context.Result = new JsonResult(exception.Message);
    }
}

Then apply the above attribute to your controller. 然后将以上属性应用于您的控制器。

[Route("api/[controller]")]
[CustomExceptionFilter]
public class ValuesController : Controller
{
     // GET: api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        throw new Exception("Suckers");
        return new string[] { "value1", "value2" };
    }
}

Rather than raising and catching an exception, how about you simplify your action to: 而不是提出并捕获异常,你如何简化你的行动:

// GET: api/customers/{id}
[HttpGet("{id}", Name = "GetCustomer")]
public IActionResult GetById(int id)
{
    var customer = _customersService.GetCustomerById(id);

    if (customer == null)
    {
        return NotFound("Customer doesn't exist");        
    }

    return Ok(customer);
}

I wrote a blog post with some more options such as returning a JSON object instead of text. 我写了一篇博文 ,其中包含更多选项,例如返回JSON对象而不是文本。

Maybe that is helpful. 也许这很有帮助。 You can return just object and sent for example a BadRequest (HTTP CODE: 400) with your custom object as actual parameter (I just used an interpolated string here) but you can put in anything. 你可以只返回object和发送例如BadRequest (HTTP代码:400),与您的自定义object的实际参数(我只是用内插的字符串这里),但你可以把任何东西。

In your client side you can catch that error situation for example with an AJAX error handler . 在客户端,您可以捕获该错误情况,例如使用AJAX错误处理程序

// GET: api/TruckFahrerGeoData
[HttpGet]
public object GetTruckFahrerGeoData()
{

    var truckFahrerGeoDataItems = new List<TruckFahrerGeoDataViewModel>();

    var geodataItems = _context.TruckFahrerGeoData;

    foreach (var truckFahrerGeoData in geodataItems)
    {
        GeoTelemetryData geoTelemetryData = JsonConvert.DeserializeObject<GeoTelemetryData>(truckFahrerGeoData.TelemetryData);

        if (geoTelemetryData == null)
        {
            return BadRequest($"geoTelemetryData null for id: {truckFahrerGeoData.Id}");
        }
        TruckFahrerGeoDataViewModel truckFahrerGeoDataViewModel = new TruckFahrerGeoDataViewModel
        {
            Speed = geoTelemetryData.Speed,
            Accuracy = geoTelemetryData.Accuracy,
            TruckAppId = geoTelemetryData.Activity.TruckAppId,
            TruckAuftragStatusId = geoTelemetryData.Activity.TruckAuftragStatusId,
            ClId = geoTelemetryData.Activity.ClId,
            TruckAuftragLaufStatusId = geoTelemetryData.Activity.TruckAuftragLaufStatusId,
            TaskId = geoTelemetryData.Activity.TaskId,
            TruckAuftragWorkflowStatusId = geoTelemetryData.Activity.TruckAuftragWorkflowStatusId
        };

        truckFahrerGeoDataItems.Add(truckFahrerGeoDataViewModel);
    }


    return truckFahrerGeoDataItems;
}

Or an even more cleaner way with IActionResult like that way: 或者像IActionResult那样更清洁的方式:

// GET: api/TruckFahrerGeoData
[HttpGet]
public IActionResult GetTruckFahrerGeoData()
{

    var truckFahrerGeoDataItems = new List<TruckFahrerGeoDataViewModel>();

    var geodataItems = _context.TruckFahrerGeoData;

    foreach (var truckFahrerGeoData in geodataItems)
    {
        GeoTelemetryData geoTelemetryData = JsonConvert.DeserializeObject<GeoTelemetryData>(truckFahrerGeoData.TelemetryData);

        if (geoTelemetryData == null)
        {
            return BadRequest($"geoTelemetryData null for id: {truckFahrerGeoData.Id}");
        }
        TruckFahrerGeoDataViewModel truckFahrerGeoDataViewModel = new TruckFahrerGeoDataViewModel
        {
            Speed = geoTelemetryData.Speed,
            Accuracy = geoTelemetryData.Accuracy,
            TruckAppId = geoTelemetryData.Activity.TruckAppId,
            TruckAuftragStatusId = geoTelemetryData.Activity.TruckAuftragStatusId,
            ClId = geoTelemetryData.Activity.ClId,
            TruckAuftragLaufStatusId = geoTelemetryData.Activity.TruckAuftragLaufStatusId,
            TaskId = geoTelemetryData.Activity.TaskId,
            TruckAuftragWorkflowStatusId = geoTelemetryData.Activity.TruckAuftragWorkflowStatusId
        };

        truckFahrerGeoDataItems.Add(truckFahrerGeoDataViewModel);
    }


    return Ok(truckFahrerGeoDataItems);
}

I had the same problem and after some research, I found out I could use HttpClient to call my API and read the response easily. 我有同样的问题,经过一些研究,我发现我可以使用HttpClient来调用我的API并轻松读取响应。 HttpClient does not throw any error when the HTTP response contains an error code, but it sets the IsSuccessStatusCode property to false. 当HTTP响应包含错误代码时,HttpClient不会抛出任何错误,但它会将IsSuccessStatusCode属性设置为false。

This is my function using the HttpClient. 这是我使用HttpClient的功能。 I call this from my controller. 我从我的控制器那里打电话。

  public static async Task<HttpResponseMessage> HttpClientPost(string header, string postdata, string url)
        {
            string uri = apiUrl + url;
            using (var client = new HttpClient())
            {
                //client.BaseAddress = new Uri(uri);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", header);
                HttpResponseMessage response = await client.PostAsync(uri, new StringContent(postdata));

                return response;
            }
        }

This is my controller code, where I call the function and read the response and determine whether I have an error or not and respond accordingly. 这是我的控制器代码,我调用该函数并读取响应并确定是否有错误并做出相应的响应。 Note that I am checking the IsSuccessStatusCode. 请注意,我正在检查IsSuccessStatusCode。

                HttpResponseMessage response;
                string url = $"Setup/AddDonor";
                var postdata = JsonConvert.SerializeObject(donor);

                response = await ApiHandler.HttpClientPost(HttpContext.Session.GetString(tokenName), postdata, url);
                //var headers = response.Headers.Concat(response.Content.Headers);
                var responseBody = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    tnxresult = JsonConvert.DeserializeObject<TnxResult>(AppFunctions.CleanResponse(responseBody));

                    return Json(new
                    {
                        ok = true,
                        message = tnxresult.Message,
                        statusCode = tnxresult.StatusCode
                    });
                }
                else
                {
                  ApiError rs = JsonConvert.DeserializeObject<ApiError>(AppFunctions.CleanResponse(responseBody));

                    return Json(new
                    {
                        ok = false,
                        message = rs.Message,
                        statusCode = rs.StatusCode
                    });

                }

My API returns error messages in JSON. 我的API以JSON格式返回错误消息。 If the call is successful, I am packing the response in JSON too. 如果调用成功,我也会在JSON中打包响应。

The crucial line of code is this one... 关键的代码是这一个......

var responseBody = await response.Content.ReadAsStringAsync();

It serializes the HTTP content to a string as an asynchronous operation. 它将HTTP内容序列化为字符串作为异步操作。

After that I can convert my JSON string to an object and access the error/success message and the Status Code too. 之后,我可以将我的JSON字符串转换为对象,并访问错误/成功消息和状态代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 调用Console.WriteLine(ex.Message)以防止出现警告消息 - Calling Console.WriteLine(ex.Message) to prevent warning message NUnit:异常性质未知时,将ex.Message写入控制台 - NUnit: Write ex.Message to Console when exception nature is unknown How can I pass the string value generated from "ex.Message" from my C# function to my Javascript function Sweet Alert, to display the error Message - How can I pass the string value generated from "ex.Message" from my C# function to my Javascript function Sweet Alert, to display the error Message 我们如何解决ex.Message =“无法将类型为&#39;MongoDB.Bson.ObjectId&#39;的对象转换为类型为&#39;MongoDB.Bson.BsonValue&#39;的对象。” - How do we resolve ex.Message = “Unable to cast object of type 'MongoDB.Bson.ObjectId' to type 'MongoDB.Bson.BsonValue'.”? 从catch块向客户端发送格式化的错误消息 - Sending formatted error message to client from catch block 在客户端处理OData错误 - Handling OData Error in client 处理服务器向客户端发送大量消息 - Handling server sending a lot of messages to a client 将消息发送到队列时出错 - Error sending message to queue 由于异常而导致的错误消息处理 - Error message handling due to exceptions C# - Websocket - 将消息发送回客户端 - C# - Websocket - Sending Message Back To Client
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM