繁体   English   中英

使用JSON在两个C#程序之间传递异常

[英]Passing exceptions between two C# programs using JSON

我有一个Web API,它向执行某些任务/命令的Windows服务发出HTTP请求。

如果我的'service'抛出异常,那么我想使用JSON将该异常传递回Web API。 然后我想将异常反序列化回异常对象并抛出它。

我的代码:

Web API和服务之间的共享异常:

public class ConnectionErrorException : Exception
{
    public ConnectionErrorException()
    {
    }
    public ConnectionErrorException(String message)
        : base(message)
    {
    }
}

现在在我的服务中,我有以下代码:

       ... 
       try
        {
            result = await ExecuteCommand(userId);
            //If reached here nothing went wrong, so can return an OK result
            await p.WriteSuccessAsync();
        }
        catch (Exception e)
        {
            //Some thing went wrong. Return the error so they know what the issue is
            result = e;
            p.WriteFailure();
        }
        //Write the body of the response:

        //If the result is null there is no need to send any body, the 200 or 400 header is sufficient
        if (result != null)
        {
            var resultOutput = JsonConvert.SerializeObject(result);
            await p.OutputStream.WriteAsync(resultOutput);
        }
        ...

所以在这里我返回一个JSON对象。 实际的响应对象,或者恰好发生的异常。

然后,这里是Web API中的代码,它向服务发出请求:

  // Make request
            HttpResponseMessage response = await client.PostAsJsonAsync(((int)(command.CommandId)).ToString(), command);
            if (response.IsSuccessStatusCode)
            {
                return await response.Content.ReadAsStringAsync();
            }
            else
            {
                var exception = HandleErrorResponse(await response.Content.ReadAsStringAsync());
                var type = exception.GetType();
                //TODO: try and determine which exact exception it is.
                throw exception;
            }

现在,如果响应成功,我只返回字符串内容。 如果请求失败,我尝试将json响应传递给异常。 但是我必须像往常一样将它传递给基本异常 - 不知道它到底是什么类型。 但是当我调试并在异常上添加一个看门狗时。 有一个参数_className ,表示'Domain.Model.Exceptions.API.ConnectionErrorException`。

问题:如何确定返回了哪个异常并将其反序列化为正确的异常,以便我可以再次抛出它。 我需要知道确切的异常类型,因为我在Web API的服务层中处理了所有不同的异常。

以下是为ConnectionErrorException返回的json的示例:

{
    "ClassName": "Domain.Model.Exceptions.API.ConnectionErrorException",
    "Message": null,
    "Data": null,
    "InnerException": null,
    "HelpURL": null,
    "StackTraceString": "",
    "HResult": -2146233088,
    "Source": "LinkProvider.Logic",
    "WatsonBuckets": null
}

用以下代码块替换您的异常处理。

else
{
    var response = await response.Content.ReadAsStringAsync();
    var exception = JsonConvert.DeserializeObject<Exception>(response);
    // your handling logic here
    Console.WriteLine(exception);
}

因此,如果服务抛出new NotImplementedException("I haz error!") ,上面会打印出System.NotImplementedException: I haz error!


这是使用MVVMLightJSON.net的快速,独立的示例。 假设你有sender

public class Sender
{
    public Sender()
    {
        Messenger.Default.Register<NotificationMessage>(this, message =>
            {
                if ((Type)message.Target == typeof(Sender))
                   GotResponse(message.Notification);
            });    
    }

    public void SendRequest(string request)
    {
        Console.WriteLine("sending:{0}", request);
        Messenger.Default.Send(
            new NotificationMessage(this, typeof(Receiver), request));
    }

    private void GotResponse(string response)
    {
        Console.WriteLine("received:{0}", response);
        if (response.Equals("ok"))
            return;

        Exception exception = JsonConvert.DeserializeObject<Exception>(response);
        Console.WriteLine("exception:{0}", exception);

        try
        {
            throw exception;
        }
        catch (Exception e)
        {
            Console.WriteLine("Indeed, it was {0}", e);
        }
    }
}

receiver

public class Receiver
{
    public Receiver()
    {
        Messenger.Default.Register<NotificationMessage>(this, message =>
            {
                if ((Type)message.Target == typeof(Receiver))
                    GotRequest(message.Notification);
            }); 
    }

    public void SendResponse(string response)
    {
        Messenger.Default.Send(new NotificationMessage(this, typeof(Sender), response));
    }

    public void GotRequest(string request)
    {
        string response = !string.IsNullOrWhiteSpace(request) ? 
                          "ok" : 
                          JsonConvert.SerializeObject(new NotImplementedException("I haz error!"));

        SendResponse(response);
    }
}

然后跟着“激活”

var sender = new Sender();
var receiver = new Receiver();
sender.SendRequest("my request");
sender.SendRequest(null);

会打印出来的

发送:我的要求
好评:OK

发送:
收到:{“ClassName”:“System.NotImplementedException”,“Message”:“...”,“WatsonBuckets”:null}

异常:System.NotImplementedException:我发生错误!

确实,它是System.NotImplementedException:我出错! at WpfApplication1.View.Sender.GotResponse(String response)in ...

您可以保留C# dynamic对象的例外,然后将其序列化为JSON,然后从Windows服务返回它。 再次在Web API上,您将该JSON反序列化并保留为动态对象。 通过这种方式,您不必担心实际的异常类型。 在任何例外情况下你都可以扔掉它。 如果你想知道异常的实际类型,那么你可以编写这样的代码,其中tempDatatempData之后的dynamic对象:

Type exceptionType = ((ObjectHandle)tempData).Unwrap().GetType();

然后相应地处理异常

希望这可以帮助 :)

首先,为了能够反序列化异常JSON,我被迫向ConnectionErrorException类添加了一个额外的构造函数:

public class ConnectionErrorException : Exception
{
    // ... rest of the code

    protected ConnectionErrorException(SerializationInfo info, StreamingContext context) 
        : base(info, context)
    {
    }
}

这是一个已知的问题。 例如,检查此问题

接下来,我将首先读取ClassName属性的值,然后根据该值将其反序列化为所需的类型。 我认为为此创建一些帮助类是个好主意:

public static class JsonHelper
{
    public static bool IsInstanceOf<T>(this JsonObject jsonObject)
    {
        if (jsonObject == null || !jsonObject.ContainsKey("ClassName"))
        {
            return false;
        }

        return jsonObject["ClassName"] == typeof(T).FullName;
    }
}

然后您的代码可能如下所示:

var jsonObject = JsonObject.Parse(json);
if(jsonObject.IsInstanceOf<ConnectionErrorException>())
{
    var connectionErrorException = 
        JsonConvert.DeserializeObject<ConnectionErrorException>(json);
}

暂无
暂无

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

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