使ASP.NET WCF将字典转换为JSON,省略“Key”和“Value”标记

这是我的困境。 我正在使用一个RESTful ASP.NET服务,试图获得一个函数来返回这种格式的JSONstring:

{"Test1Key":"Test1Value","Test2Key":"Test2Value","Test3Key":"Test3Value"} 

但是我用这种格式来取代它:

 [{"Key":"Test1Key","Value":"Test1Value"}, {"Key":"Test2Key","Value":"Test2Value"}, {"Key":"Test3Key","Value":"Test3Value"}] 

我的方法如下所示:

 [OperationContract] [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)] public Dictionary<string, string> Test(String Token) { if (!IsAuthorized(Token)) return null; if (!IsSecure(HttpContext.Current)) return null; Dictionary<string, string> testresults = new Dictionary<string, string>(); testresults.Add("Test1Key", "Test1Value"); testresults.Add("Test2Key", "Test2Value"); testresults.Add("Test3Key", "Test3Value"); return testresults; } 

有什么办法可以摆脱那些“关键”和“价值”标签只使用内置的ASP.NET工具? (即,我宁愿不使用JSON.NET,如果它是可以避免的)

非常感谢! 🙂

.NET字典类将不会以您描述的方式进行序列化。 但是,如果你创build自己的类,并包装字典类,那么你可以重写序列化/反序列化方法,并能够做你想做的。 看下面的例子,注意“GetObjectData”方法。

  [Serializable] public class AjaxDictionary<TKey, TValue> : ISerializable { private Dictionary<TKey, TValue> _Dictionary; public AjaxDictionary() { _Dictionary = new Dictionary<TKey, TValue>(); } public AjaxDictionary( SerializationInfo info, StreamingContext context ) { _Dictionary = new Dictionary<TKey, TValue>(); } public TValue this[TKey key] { get { return _Dictionary[key]; } set { _Dictionary[key] = value; } } public void Add(TKey key, TValue value) { _Dictionary.Add(key, value); } public void GetObjectData( SerializationInfo info, StreamingContext context ) { foreach( TKey key in _Dictionary.Keys ) info.AddValue( key.ToString(), _Dictionary[key] ); } } 

如果有人在客户端有这个问题:从奇怪的{Key:“x”,值:“y”}数组转换为{x:“y”}对象可以在一行JS:

 var o = i.reduce(function (p, c, a, i) { p[c.Key] = c.Value; return p }, {}); 

我是从服务返回的数组,o正是你真正想要的。

最好的祝福

几个月前,我遇到了这个问题,并在这里发布了一个不太理想的简洁问题: configurationWCF数据合同以获得正确的JSON响应

这个问题与我在这里发布的问题一样:总之,在WCF的上下文中,标准的asp.net序列化工具对于一个字典将返回一个ARRAY而不是一个键/值对JSON OBJECT。 我张贴我的解决scheme,虽然我确实诉诸使用JSON.NET(我意识到海报试图避免)为我工作。 不过,也许这对别人会有帮助。

 Function myDictionaryFunction () As Stream Implements IMywebservice.myDictionaryFunction Dim myKeyValuePairObject As Object = New Dynamic.ExpandoObject Dim myDictionary = DirectCast(myKeyValuePairObject, IDictionary(Of String, Object)) myDictionary.Add("Test1Key", "Test1Value") myDictionary.Add("Test2Key", "Test2Value") myDictionary.Add("Test3Key", "Test3Value") strJson = JsonConvert.SerializeObject(myKeyValuePairObject) Dim resultBytes As Byte() = Encoding.UTF8.GetBytes(strJson) WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain" Return New MemoryStream(resultBytes) End Function 

结果:

 {"Test1Key":"Test1Value","Test2Key":"Test2Value","Test3Key":"Test3Value"} 

expando对象就像一个魅力。 但是为了使它工作,你必须强制WCF返回纯文本,人们认为这很容易,但事实并非如此。 你必须实现一个RawContentTypeMapperbuild议这里: http ://referencesource.microsoft.com/#System.ServiceModel.Web/System/ServiceModel/Channels/RawContentTypeMapper.cs …然后,你必须弄乱你的网站。configuration文件是这样的:

  <customBinding> <binding name="RawReceiveCapable"> <webMessageEncoding webContentTypeMapperType="myNamespace.RawContentTypeMapper, myLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <httpTransport manualAddressing="true" maxReceivedMessageSize="524288000" transferMode="Streamed" /> </binding> </customBinding> 

我是第一个承认这个解决scheme可能不会获得任何奖项的优雅。 但是,它工作并返回WCF Web服务的原始内容,如果需要的话,将给您一些额外的控制如何序列化您的WCF数据有效载荷。 由于实现这个,我已经越来越多地迁移到ASP.NET Web API(这使得返回RESTful比WCF,IMO更容易)。

在@ MarkisT的优秀解决scheme上略有扩展,您可以修改序列化构造函数以从相同JSON重新创build这些字典中的一个(从而允许您将AjaxDictionary作为服务参数),如下所示:

 public AjaxDictionary( SerializationInfo info, StreamingContext context ) { _Dictionary = new Dictionary<TKey, TValue>(); foreach (SerializationEntry kvp in info) { _Dictionary.Add((TKey)Convert.ChangeType(kvp.Name, typeof(TKey)), (TValue)Convert.ChangeType(kvp.Value, typeof(TValue))); } } 

避免json中的“__type”…

在webapi.config中,有几个选项(看最后一个):

  // To disable tracing in your application, please comment out or remove the following line of code // For more information, refer to: http://www.asp.net/web-api //config.EnableSystemDiagnosticsTracing(); // Use camel case for JSON data. config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); // The setting will let json.net to save type name in the payload if the runtime type is different with the declare type. // When you post it back, json.net will deserialize the payload to the type you specified in the payload. // source: http://stackoverflow.com/questions/12858748/asp-net-webapi-posting-collection-of-subclasses //config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;