使 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 Core 中将对象转换为 Json

我应该通过 ASP.NET MVC 操作还是 WCF 公开 Web 方法?

在将 json 反序列化为对象时,使用 jackson 将 asp.net / MS 专有 json Dateformat 转换为 java8 LocalDateTime