简体   繁体   English

如何捕获异常并将其作为 json 消息发送?

[英]How can I catch an exception and send it as json message?

I wrote a code but for some reason it doesn't work...can you tell me what's wrong?我写了一个代码,但由于某种原因它不起作用......你能告诉我有什么问题吗? I want the app not to stop when I get an exception, only to send that exception back as a json message.我希望应用程序在遇到异常时不要停止,只是将该异常作为 json 消息发送回来。

Startup.cs Configure method: Startup.cs 配置方法:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v2/swagger.json", "My API");
            });
        }
        //this is the question...?
        app.UseExceptionHandler(c => c.Run(async context =>
        {
                var exception = context.Features.Get<IExceptionHandlerPathFeature>().Error;
                var response = new { Msg = exception.Message };
                await context.Response.WriteAsJsonAsync(response);
        }));

        app.UseHttpsRedirection();

        app.UseStaticFiles();

        app.UseRouting();

        app.UseCors(x => x
           .AllowAnyMethod()
           .AllowAnyHeader()
           .SetIsOriginAllowed(origin => true)
           .AllowCredentials());

        app.UseAuthentication();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.MapHub<EventHub>("/events");
        });
    }

Logic the method where I throw an exception:逻辑我抛出异常的方法:

public IEnumerable<object> Search(string text)
    {
        if (text.Length >= 3)
        {
            var result = new List<object>
            {
                clubRepository.GetAll().Where(club => club.ClubName.Contains(text)),
                playerRepository.GetAll().Where(player => player.PlayerName.Contains(text)),
                managerRepository.GetAll().Where(manager => manager.ManagerName.Contains(text)),
                stadiumRepository.GetAll().Where(stadium => stadium.StadiumName.Contains(text))
            };

            return result;
        }
        else
        {
            throw new ArgumentException("The text is not long enough!");
        }
    }

So I would like to get this exception message as json!所以我想把这个异常消息作为json!

Now it is happening --> Image1现在它正在发生-> Image1

I want that to happen --> Image2我希望这种情况发生-> Image2

You can extract exception elements as a key value in a dictionary.您可以提取异常元素作为字典中的键值。

And serialize that into JSON.并将其序列化为 JSON。

Inspired by this answer , here is my method to extract key/value from exception:受此答案的启发,这是我从异常中提取键/值的方法:

public static Dictionary<string, string> GetExceptionDetails(Exception exception)
{
    var properties = exception.GetType()
        .GetProperties();
    var fields = properties
        .Select(property => new
        {
            Name = property.Name,
            Value = property.GetValue(exception, null)
        })
        .Select(x => $"{x.Name} = {(x.Value != null ? x.Value.ToString() : string.Empty)}")
        .ToDictionary(k => k, v => v);
    return fields;
}

For my test I have done this:对于我的测试,我已经这样做了:

private static void CallSome()
{
    throw new Exception("xx");
}

in your try/catch you do the following:在您的 try/catch 中,您执行以下操作:

try
{
    CallSome();
}
catch (Exception e)
{
    string str = JsonConvert.SerializeObject(GetExceptionDetails(e));
    Console.WriteLine(str);
}

This will return you a JSON payload.这将返回一个 JSON 有效负载。

I use dotnet 6 console app.我使用 dotnet 6 控制台应用程序。 I have also installed the Newtonsoft.Json package.我还安装了 Newtonsoft.Json 包。 You can also you dotnet JsonSerializer:您也可以使用 dotnet JsonSerializer:

var str = JsonSerializer.Serialize(GetExceptionDetails(e));

Note: it also worth reading this also this.注意:这也值得一

You can use Middleware to handle any exception.您可以使用中间件来处理任何异常。

First: Create a ErrorHandlerMiddleware.cs like below.首先:创建一个ErrorHandlerMiddleware.cs ,如下所示。

public class ErrorHandlerMiddleware
{
    private readonly RequestDelegate _next;
    public ErrorHandlerMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    public async Task Invoke(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception error)
        {
            var response = context.Response;
            //Set response ContentType
            response.ContentType = "application/json";

            //Set custome error message for response model
            var responseContent = new ResponseContent()
            {
                error = error.Message
            };
            //handler many Exception types
            switch (error)
            {
                case ArgumentException _ae:
                    response.StatusCode = StatusCodes.Status400BadRequest;
                    break;
                default:
                    response.StatusCode = StatusCodes.Status500InternalServerError;
                    break;
            }
            //Using Newtonsoft.Json to convert object to json string
            var jsonResult = JsonConvert.SerializeObject(responseContent);
            await response.WriteAsync(jsonResult);
        }
    }
    //Response Model
    public class ResponseContent
    {
        public string error { get; set; }
    }
}

Next: In Startup.cs , use the middleware Next: 在Startup.cs中,使用中间件

app.UseMiddleware<ErrorHandlerMiddleware>();

Here is project structure of my simple example :这是我的简单示例的项目结构:

在此处输入图像描述

Goodluck!祝你好运!

I don't know if you misunderstood but your app is only stopping because you are running it inside VS Code (Debug Mode).我不知道您是否误解了,但您的应用程序只是因为您在 VS Code(调试模式)中运行它而停止。 If you run your app externally (in command, run "dotnet run") you'll see that the app will not stop.如果您在外部运行您的应用程序(在命令中,运行“dotnet run”),您会看到该应用程序不会停止。

Now, it's just an advice.现在,这只是一个建议。 Your app is already sending back the json but with status code 500 (internal server error).您的应用已经在发回 json,但状态码为 500(内部服务器错误)。 A better practice for validation errors, is returning as bad request (status code 400).验证错误的更好做法是返回错误请求(状态代码 400)。 You can add one line like below.您可以添加一行,如下所示。

app.UseExceptionHandler(c => c.Run(async context =>
{
    var exception = context.Features.Get<IExceptionHandlerPathFeature>().Error;
    var response = new { Msg = exception.Message };

    context.Response.StatusCode = (int)HttpStatusCode.BadRequest;

    await context.Response.WriteAsJsonAsync(response);

}));

Then, if you want to improve a little more.然后,如果你想再提高一点。 You can replace exceptions with notification pattern.您可以用通知模式替换异常。 Here are some links if you are interested.如果您有兴趣,这里有一些链接。

https://martinfowler.com/articles/replaceThrowWithNotification.html https://timdeschryver.dev/blog/creating-a-new-csharp-api-validate-incoming-requests https://martinfowler.com/articles/replaceThrowWithNotification.html https://timdeschryver.dev/blog/creating-a-new-csharp-api-validate-incoming-requests

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM