让ASP.. NET WCF将字典转换为JSON,省略';key ';,“Value"标签
本文关键字:key ASP Value 标签 quot NET WCF 转换 字典 JSON 省略 | 更新日期: 2023-09-27 18:10:10
这是我的困境。我使用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;
}
是否有任何方法我可以摆脱那些"键"answers"值"标签只使用内置的ASP。网络工具?(也就是说,我宁愿不使用JSON。. NET,如果可以避免的话)
非常感谢!:)
. 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] );
}
}
稍微扩展@MarkisT的出色解决方案,您可以修改序列化构造函数以从相同的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)));
}
}
如果有人在客户端有这个问题:从那个奇怪的{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为您实际需要的数组。
我在几个月前遇到了这个问题,并在这里发布了一个不太理想的简洁问题:配置WCF数据契约以获得正确的JSON响应
我当时的问题原来是相同的更精确地张贴在这里的问题,简而言之:在WCF的上下文中,标准的asp.net序列化工具将,对于一个字典,返回一个数组,而不是一个键/值对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...然后你就得乱搞你的网了。配置文件如下:
<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容易得多)。
避免在json中使用"__type"…
中的webapi。配置,有几个选项(看最后一个):
// 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;