我们正在考虑用JSON(WCF或其他)调用替换(一些或许多)“经典” SOAP XML
WCF调用,因为其开销较低且易于直接在Javascript中使用。现在,我们刚刚在Web服务中添加了一个额外的Json端点,并在某些操作中添加了WebInvoke属性并对其进行了测试。使用C#.Net客户端或Javascript客户端,一切正常。到目前为止,一切都很好。
但是,似乎将大JSON字符串反序列化为C#.Net中的对象比反序列化SOAP
XML慢得多。两者都使用DataContract和DataMember属性(完全相同的DTO)。我的问题是:这是预期的吗?我们可以做些什么来优化此性能?或者,我们应该只对较小的请求考虑JSON,但确实注意到性能有所提高。
到目前为止,我们已经选择JSON.net进行此测试,即使在此测试用例中未显示它,也应该比.Net
JSON序列化要快。不知何故,ServiceStack反序列化根本不起作用(无错误,为IList返回null)。
为了进行测试,我们进行了服务呼叫以收集房间列表。它返回一个GetRoomListResponse,并且在返回5个虚拟房间的情况下,JSON如下所示:
{"Acknowledge":1,"Code":0,"Message":null,"ValidateErrors":null,"Exception":null,"RoomList":[{"Description":"DummyRoom","Id":"205305e6-9f7b-4a6a-a1de-c5933a45cac0","Location":{"Code":"123","Description":"Location 123","Id":"4268dd65-100d-47c8-a7fe-ea8bf26a7282","Number":5}},{"Description":"DummyRoom","Id":"aad737f7-0caa-4574-9ca5-f39964d50f41","Location":{"Code":"123","Description":"Location 123","Id":"b0325ff4-c169-4b56-bc89-166d4c6d9eeb","Number":5}},{"Description":"DummyRoom","Id":"c8caef4b-e708-48b3-948f-7a5cdb6979ef","Location":{"Code":"123","Description":"Location 123","Id":"11b3f513-d17a-4a00-aebb-4d92ce3f9ae8","Number":5}},{"Description":"DummyRoom","Id":"71376c49-ec41-4b12-b5b9-afff7da882c8","Location":{"Code":"123","Description":"Location 123","Id":"1a188f13-3be6-4bde-96a0-ef5e0ae4e437","Number":5}},{"Description":"DummyRoom","Id":"b947a594-209e-4195-a2c8-86f20eb883c4","Location":{"Code":"123","Description":"Location 123","Id":"053e9969-d0ed-4623-8a84-d32499b5a8a8","Number":5}}]}
响应和DTO如下所示:
[DataContract(Namespace = "bla")]
public class GetRoomListResponse
{
[DataMember]
public IList<Room> RoomList;
[DataMember]
public string Exception;
[DataMember]
public AcknowledgeType Acknowledge = AcknowledgeType.Success;
[DataMember]
public string Message;
[DataMember]
public int Code;
[DataMember]
public IList<string> ValidateErrors;
}
[DataContract(Name = "Location", Namespace = "bla")]
public class Location
{
[DataMember]
public Guid Id { get; set; }
[DataMember]
public int Number { get; set; }
[DataMember]
public string Code { get; set; }
[DataMember]
public string Description { get; set; }
}
[DataContract(Name = "Room", Namespace = "bla")]
public class Room
{
[DataMember]
public Guid Id { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public Location Location { get; set; }
}
然后我们的测试代码如下:
static void Main(string[] args)
{
SoapLogin();
Console.WriteLine();
SoapGetRoomList();
SoapGetRoomList();
SoapGetRoomList();
SoapGetRoomList();
SoapGetRoomList();
SoapGetRoomList();
SoapGetRoomList();
Console.WriteLine();
JsonDotNetGetRoomList();
JsonDotNetGetRoomList();
JsonDotNetGetRoomList();
JsonDotNetGetRoomList();
JsonDotNetGetRoomList();
JsonDotNetGetRoomList();
JsonDotNetGetRoomList();
Console.ReadLine();
}
private static void SoapGetRoomList()
{
var request = new TestServiceReference.GetRoomListRequest()
{
Token = Token,
};
Stopwatch sw = Stopwatch.StartNew();
using (var client = new TestServiceReference.WARPServiceClient())
{
TestServiceReference.GetRoomListResponse response = client.GetRoomList(request);
}
sw.Stop();
Console.WriteLine("SOAP GetRoomList: " + sw.ElapsedMilliseconds);
}
private static void JsonDotNetGetRoomList()
{
var request = new GetRoomListRequest()
{
Token = Token,
};
Stopwatch sw = Stopwatch.StartNew();
long deserializationMillis;
using (WebClient client = new WebClient())
{
client.Headers["Content-type"] = "application/json";
client.Encoding = Encoding.UTF8;
string requestData = JsonConvert.SerializeObject(request, JsonSerializerSettings);
var responseData = client.UploadString(GetRoomListAddress, requestData);
Stopwatch sw2 = Stopwatch.StartNew();
var response = JsonConvert.DeserializeObject<GetRoomListResponse>(responseData, JsonSerializerSettings);
sw2.Stop();
deserializationMillis = sw2.ElapsedMilliseconds;
}
sw.Stop();
Console.WriteLine("JSON.Net GetRoomList: " + sw.ElapsedMilliseconds + " (deserialization time: " + deserializationMillis + ")");
}
private static JsonSerializerSettings JsonSerializerSettings
{
get
{
var serializerSettings = new JsonSerializerSettings();
serializerSettings.CheckAdditionalContent = false;
serializerSettings.ConstructorHandling = ConstructorHandling.Default;
serializerSettings.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
serializerSettings.DefaultValueHandling = DefaultValueHandling.Ignore;
serializerSettings.NullValueHandling = NullValueHandling.Ignore;
serializerSettings.ObjectCreationHandling = ObjectCreationHandling.Replace;
serializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.None;
serializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Error;
return serializerSettings;
}
}
现在,我们以返回50、500和5000个房间的方式运行了该应用程序。对象不是很复杂。
这些是结果;时间以毫秒为单位:
50间客房:
SOAP GetRoomList: 37
SOAP GetRoomList: 5
SOAP GetRoomList: 4
SOAP GetRoomList: 4
SOAP GetRoomList: 9
SOAP GetRoomList: 5
SOAP GetRoomList: 5
JSON.Net GetRoomList: 289 (deserialization time: 91)
JSON.Net GetRoomList: 3 (deserialization time: 0)
JSON.Net GetRoomList: 2 (deserialization time: 0)
JSON.Net GetRoomList: 2 (deserialization time: 0)
JSON.Net GetRoomList: 2 (deserialization time: 0)
JSON.Net GetRoomList: 2 (deserialization time: 0)
JSON.Net GetRoomList: 2 (deserialization time: 0)
500间客房:
SOAP GetRoomList: 47
SOAP GetRoomList: 9
SOAP GetRoomList: 8
SOAP GetRoomList: 8
SOAP GetRoomList: 8
SOAP GetRoomList: 8
SOAP GetRoomList: 8
JSON.Net GetRoomList: 301 (deserialization time: 100)
JSON.Net GetRoomList: 12 (deserialization time: 8)
JSON.Net GetRoomList: 12 (deserialization time: 8)
JSON.Net GetRoomList: 12 (deserialization time: 8)
JSON.Net GetRoomList: 11 (deserialization time: 8)
JSON.Net GetRoomList: 11 (deserialization time: 8)
JSON.Net GetRoomList: 15 (deserialization time: 12)
5000间客房:
SOAP GetRoomList: 93
SOAP GetRoomList: 51
SOAP GetRoomList: 58
SOAP GetRoomList: 60
SOAP GetRoomList: 53
SOAP GetRoomList: 53
SOAP GetRoomList: 51
JSON.Net GetRoomList: 405 (deserialization time: 175)
JSON.Net GetRoomList: 107 (deserialization time: 79)
JSON.Net GetRoomList: 108 (deserialization time: 82)
JSON.Net GetRoomList: 112 (deserialization time: 85)
JSON.Net GetRoomList: 105 (deserialization time: 79)
JSON.Net GetRoomList: 111 (deserialization time: 81)
JSON.Net GetRoomList: 110 (deserialization time: 82)
我正在发布模式下运行该应用程序。客户端和服务器都在同一台计算机上。如您所见,与WCF
SOAP使用的XML到对象的映射相比,使用JSON对许多(相同类型的)对象进行反序列化要花费更多的时间。糟糕的是,反序列化比使用SOAP进行整个Web服务调用要花费更多的时间。
对此有解释吗?XML(或WCF
SOAP实现)在这方面是否提供了很大的优势,或者我可以在客户端进行任何更改(我宁愿不更改服务,但可以更改客户端DTO可以接受)以尝试提高绩效?感觉好像我已经在JSON.net端选择了一些设置,这些设置应该使其比默认设置更快,不是吗?这里的瓶颈似乎是什么?
我花了更多时间阅读有关JSON.NET内部的信息,我的结论是,速度缓慢主要是由 反射 引起的。
在JSON.NET站点上,我发现了一些不错的性能提示,并且尝试了几乎所有方法(JObject.Parse,自定义转换器等),但是我无法实现任何显着的性能改进。然后,我阅读了整个网站上最重要的说明:
如果性能很重要,并且您不介意获得更多代码,那么这是您的最佳选择。在此处阅读有关使用JsonReader / JsonWriter的更多信息
因此,我听了建议,并实现了JsonReader的基本版本以有效地读取字符串:
var reader = new JsonTextReader(new StringReader(jsonString));
var response = new GetRoomListResponse();
var currentProperty = string.Empty;
while (reader.Read())
{
if (reader.Value != null)
{
if (reader.TokenType == JsonToken.PropertyName)
currentProperty = reader.Value.ToString();
if (reader.TokenType == JsonToken.Integer && currentProperty == "Acknowledge")
response.Acknowledge = (AcknowledgeType)Int32.Parse(reader.Value.ToString());
if (reader.TokenType == JsonToken.Integer && currentProperty == "Code")
response.Code = Int32.Parse(reader.Value.ToString());
if (reader.TokenType == JsonToken.String && currentProperty == "Message")
response.Message = reader.Value.ToString();
if (reader.TokenType == JsonToken.String && currentProperty == "Exception")
response.Exception = reader.Value.ToString();
// Process Rooms and other stuff
}
else
{
// Process tracking the current nested element
}
}
我认为练习很清楚, 毫无疑问,这是您可以从JSON.NET中获得的最佳性能 。
仅此有限的代码比Deserialize
我有500个房间的盒子上的版本快12倍,但是映射当然没有完成。但是,我很确定在最坏的情况下它至少比反序列化快5倍。
查看此链接,以获取有关JsonReader以及如何使用它的更多信息:
http://james.newtonking.com/json/help/html/ReadingWritingJSON.htm
问题内容: 我有一个非常不理想的情况,要求我反序列化JSON,其中值是JSON.NET的字段名称。假设我具有以下结构正确的JSON: 使用JSON.NET将其反序列化为CLR对象非常容易: 但是,在当前情况下,我有以下可怕的JSON,就值而言,它等效于上述JSON: 如您所见,field不是数组。这是一个包含其他值作为对象的对象,其唯一键作为其字段名称(这太可怕了)。使用JSON.NET 将JSO
问题内容: 我想避免在序列化数据时重新发明轮子。我知道一些序列化彼此链接的对象的方法,但是范围从编写一些代码到编写大量用于序列化的代码,我希望避免这种情况。必须有一些通用的解决方案。 假设我有一个这样的结构: 我想将数据序列化为这样的东西: 在此,假设名称是唯一的,则链接仅作为名称序列化。链接也可以是“ family.persons.0”或生成的唯一ID等。 要求: 格式必须是 人类可读的 ,最好
问题内容: 我正在使用以下类型定义Json.NET属性,然后在其方法内部使用Json.NET对其进行序列化: 我的问题是,它将返回“ {}”。这是为什么?以前在工作。我所做的唯一更改是更改了OptIn而不是OptOut,因为我希望包含的属性少于保留的属性。 问题答案: 如Newtonsoft在本期中所述,Json.NET实际上支持属性。但是,当相应的“真实”成员是属性时,似乎Json.NET要求成
问题内容: 想知道您是否可以帮助我创建一个VB.Net类,在其中可以反序列化以下JSON响应: 我有以下几点: 和 我正在使用Newtonsoft.Json反序列化: 如果我知道actor元素始终遵循相同的格式- 有没有一种方法可以解析JSON响应,以便Player.Likes.Actors是一个List(Of Actor)而不是我现在拥有的List(OfList(Of String))? 问题答
本文向大家介绍.NET中JSON的序列化和反序列化的几种方式,包括了.NET中JSON的序列化和反序列化的几种方式的使用技巧和注意事项,需要的朋友参考一下 一、什么是JSON JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立 于编程语言的文本格式来存
问题内容: 我正在尝试使用自定义将一些JSON反序列化为各种子类 我几乎遵循了这一点。 我的抽象基类: 而我的派生: 只是一个包含一些字符串常量的静态类。 JSON文件反序列化如下: 现在,我的问题是,每当我运行代码时,都会出现以下错误: 有问题的Json文件如下所示: 在我看来,反序列化嵌套对象有麻烦,我该如何解决? 问题答案: 首先,错过了您的json中的菜单项“ Submenus Test”