使 ASP.NET WCF 将字典转换为 JSON,省略“键”和“值”标签
Posted
技术标签:
【中文标题】使 ASP.NET WCF 将字典转换为 JSON,省略“键”和“值”标签【英文标题】:Make ASP.NET WCF convert dictionary to JSON, omitting "Key" & "Value" tags 【发布时间】:2011-11-27 06:04:17 【问题描述】:这是我的困境。我正在使用一个 RESTful ASP.NET 服务,试图让一个函数以这种格式返回一个 JSON 字符串:
"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)
非常感谢! :)
【问题讨论】:
【参考方案1】:.NET 字典类不会以您描述的方式以外的任何其他方式进行序列化。但是,如果您创建自己的类并包装字典类,那么您可以覆盖序列化/反序列化方法并能够做您想做的事情。请参见下面的示例并注意“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] );
【讨论】:
哇!这非常接近我所需要的……只有一件事。有没有办法不包含“__type”键/值对?我宁愿使用它的人没有看到那个价值,但我不知道如何摆脱它。 哦,是的,我不记得 .NET 4.0 是否修复了这个问题,或者我是否做了其他事情来摆脱它。我也用谷歌搜索,发现这个也可以:***.com/questions/627356/… 不幸的是,我不能给你一个赞成票,因为我没有足够的声誉 - 不过我会将此标记为最佳答案,因为它最接近我的需要(我只是'无法摆脱 __type 的东西)。 您是否尝试将 DataContractAttribute 添加到类中并将 DataMemberAttribute 添加到正在序列化的对象的成员中?? 不知何故这个例子对我不起作用。执行 GET 将导致“无响应”,但我在调试器中看到调用了 GetObjectData。【参考方案2】:在 @MarkisT 的优秀 solution 基础上稍作扩展,您可以修改序列化构造函数以从相同的 JSON 重新创建其中一个字典(从而允许您将 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)));
【讨论】:
【参考方案3】:如果有人在客户端遇到这个问题:从那个奇怪的 Key: "x", Value:"y" 数组到 x: "y" 对象的转换可以在一行中完成JS:
var o = i.reduce(function (p, c, a, i) p[c.Key] = c.Value; return p , );
i 是从服务返回的数组,o 是你真正想要的。
最好的问候
【讨论】:
【参考方案4】:几个月前我遇到了这个问题,并在这里发布了一个不太简洁的问题:Configuring WCF data contract for proper JSON response
我当时遇到的问题与此处发布的更精确的问题相同,简而言之:在 WCF 的上下文中,标准的 asp.net 序列化工具对于字典将返回一个 ARRAY 而不是键/值对 json 对象。我发布了对我有用的解决方案,尽管我确实使用了 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 返回纯文本,人们认为这很容易,但事实并非如此。您必须按照此处的建议实施 RawContentTypeMapper:http://referencesource.microsoft.com/#System.ServiceModel.Web/System/ServiceModel/Channels/RawContentTypeMapper.cs ...然后你必须像这样处理你的 web.config 文件:
<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>
我是第一个承认此解决方案可能不会因优雅而获得任何奖项的人。但它有效,如果需要,从 WCF Web 服务返回原始内容将为您提供一些额外的控制如何序列化您的 WCF 数据有效负载。自从实现这一点以来,我已经越来越多地迁移到 ASP.NET Web API(这使得返回 RESTful 比 WCF、IMO 更容易)。
【讨论】:
【参考方案5】:避免 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://***.com/questions/12858748/asp-net-webapi-posting-collection-of-subclasses
//config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
【讨论】:
以上是关于使 ASP.NET WCF 将字典转换为 JSON,省略“键”和“值”标签的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET MVC 如何将 ModelState 错误转换为 json
ASP.NET MVC4 Web API MediaTypeFormatter 转换器将 XElement 转换为 JSON
使用 JSON 实现带有 WCF 服务 (wshttpBinding) 的 c# asp.net 应用程序
我应该通过 ASP.NET MVC 操作还是 WCF 公开 Web 方法?
在将 json 反序列化为对象时,使用 jackson 将 asp.net / MS 专有 json Dateformat 转换为 java8 LocalDateTime