使用JSON

时间:2015-05-13 09:21:11

标签: c# json exception asp.net-web-api json.net

我有一个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
}

3 个答案:

答案 0 :(得分:2)

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

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:我出错!在   WpfApplication1.View.Sender.GotResponse(String response)in ...

答案 1 :(得分:1)

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

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

然后相应地处理异常

希望这会有所帮助:)

答案 2 :(得分:1)

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

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

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

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

接下来,我将首先读取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);
}