【问题标题】:Make ASP.NET WCF convert dictionary to JSON, omitting "Key" & "Value" tags使 ASP.NET WCF 将字典转换为 JSON,省略“键”和“值”标签
【发布时间】: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)

非常感谢! :)

【问题讨论】:

    标签: c# asp.net wcf json rest


    【解决方案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 是否修复了这个问题,或者我是否做了其他事情来摆脱它。我也用谷歌搜索,发现这个也可以:stackoverflow.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://stackoverflow.com/questions/12858748/asp-net-webapi-posting-collection-of-subclasses
                  //config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-03-31
            • 2017-09-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多