在Web Service中傳送Dictionary

有個需求,想在Web Service中傳遞Dictionary<string, string>參數,例如:

排版顯示純文字
[WebMethod]
public Dictionary<string, string> Process(Dictionary<string, string> dct)
{
    //Do something on the Dictionary
    //... blah blah blah ....
 
    return dct;
}

天不從人願,以上的寫法會產生Web Service不支援IDictionary的錯誤:

The type System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] is not supported because it implements IDictionary.

既是IDictionary的原罪,就算是換用Hashtable、ListDictionary應該也是同樣結果,測試之下果然無一倖免。

Google發現討論區有篇來自MS RD的留言,算是證實這是先天限制:

ASMX web services do not support types that implement IDictionary since V1. This is by design and was initially done since key-value constraints could not be appropriately expressed in schema.
來源: http://social.msdn.microsoft.com/Forums/en-US/asmxandxml/thread/d7cb8844-6774-4a98-8aa3-85e445af4867/

既然是By Design,就只有繞道而行。Survey了一下,找到一些建議做法:

  • 改用XML
  • 使用DataSet
  • 另外自訂Class作為參數
  • 以DictionaryEntry[]瓜代之

評估了一下,我原本想要借重的就是Dictionary
Key/Value的單純資料結構,XML為開放格式不易限制成Key/Value的形式;小小需求動用到DataSet略嫌笨重;自訂Class在編譯
時期就要確定Key的種類,不符本案例的前題。看來DictionaryEntry[]較合需求,因此我試寫如下:
(剛好Dictionary與DirectionaryEntry的雙向轉換都有示範到)

排版顯示純文字
[WebMethod]
public DictionaryEntry[] Test(System.Collections.DictionaryEntry[] entries)
{
    //用ListDictionary主要是為了稍後可以直接CopyTo轉DictionaryEntry[]
    //若有效率或其他考量,可改用其他Collection Class
    ListDictionary dct = new ListDictionary();
    foreach (DictionaryEntry de in entries)
        dct.Add(de.Key, de.Value);
    
    //Do something on the Dictionary
    //... blah blah blah ....
    if (dct.Contains("Kuso"))
        dct["Kuso"] = "殺很大";
    
    DictionaryEntry[] result = new DictionaryEntry[dct.Count];
    dct.CopyTo(result, 0);
    return result;
}

呼叫端範例如下:

排版顯示純文字
protected void Page_Load(object sender, EventArgs e)
{
    localhost.AFAWebService aws = new localhost.AFAWebService();
    aws.Credentials = CredentialCache.DefaultCredentials;
    Dictionary<string, string> dct = new Dictionary<string, string>();
    dct.Add("Kuso", "你不要走");
    //DictionaryEntry在Web Service傳遞時會被當成自訂類別
    //因此要用namespace.DictionaryEntry而非System.Collections.DictionaryEntry
    List<localhost.DictionaryEntry> lst = new List<localhost.DictionaryEntry>();
    foreach (string key in dct.Keys)
    {
        localhost.DictionaryEntry de = new localhost.DictionaryEntry();
        de.Key = key;
        de.Value = dct[key];
        lst.Add(de);
    }
    localhost.DictionaryEntry[] result = aws.Test(lst.ToArray());
    Dictionary<string, string> dctRes = new Dictionary<string, string>();
    foreach (localhost.DictionaryEntry de in result)
        dctRes.Add(de.Key.ToString(), de.Value.ToString());
    Response.Write(dct["Kuso"] + "->" + dctRes["Kuso"]);
    Response.End();
}

經過這番來回折騰,這方法看來也不怎麼簡潔。

於是,我又嘗試了Paul Welter的SerializableDictionary物件, 做法上要在Web Service與Client端都Reference這個自訂物件,而且使用Visual Studio的Add Web Reference時,自動產生的Proxy Class宣告中SerializableDictionary會被當成DataSet而失敗,因此得改成手動產生Proxy Class後再將DataSet改回SerializableDictionary:

C:\AppCodeFolder\>wsdl http: //localhost/myweb/afawebservice.asmx?WSDL /l:cs /n:localhost /out:AfaWebServiceProxy.cs
Microsoft (R) Web Services Description Language Utility
[Microsoft (R) .NET Framework, Version 2.0.50727.42]
Copyright (C) Microsoft Corporation. All rights reserved.
Writing file 'AfaWebServiceProxy.cs'.

用了SerializableDictionary後,程式碼簡化許多:

排版顯示純文字
[WebMethod]
public SerializableDictionary<string, string> Test(
 SerializableDictionary<string, string> dct)
{
    if (dct.ContainsKey("Kuso"))
        dct["Kuso"] = "殺很大";
    return dct;
}

呼叫端也很單純:

排版顯示純文字
protected void Page_Load(object sender, EventArgs e)
{
    localhost.AFAWebService aws = new localhost.AFAWebService();
    aws.Credentials = CredentialCache.DefaultCredentials;
    SerializableDictionary<string, string> dct = 
             new SerializableDictionary<string, string>();
    dct.Add("Kuso", "你不要走");
    SerializableDictionary<string, string> dctRes = aws.Test(dct);
    Response.Write(dct["Kuso"] + "->" + dctRes["Kuso"]);
    Response.End();
}

但是,這個做法需要在Web Service與Client端加入自訂元件參照、Proxy Class需要手動增加或修改,還是有些許不便。這樣看來,DataSet或XML法雖有其他缺點,但內建支援的特點,在力求簡單的場合裡,倒也值得納入考量吧!

问题:不支持Dictionary;结果:在Web Service中傳送Dictionary的更多相关文章

  1. 在Web Service中傳送Dictionary

    有個需求,想在Web Service中傳遞Dictionary<string, string>參數,例如: 排版顯示純文字 [WebMethod] public Dictionary< ...

  2. Web Service 中返回DataSet结果大小改进

    http://www.cnblogs.com/scottckt/archive/2012/11/10/2764496.html Web Service 中返回DataSet结果方法: 1)直接返回Da ...

  3. Web Service 中返回DataSet结果的几种方法

    Web Service 中返回DataSet结果的几种方法: 1)直接返回DataSet对象    特点:通常组件化的处理机制,不加任何修饰及处理:    优点:代码精减.易于处理,小数据量处理较快: ...

  4. ASP.NET Web Service中使用Session 及 Session丢失解决方法 续

    原文:ASP.NET Web Service中使用Session 及 Session丢失解决方法 续 1.关于Session丢失问题的说明汇总,参考这里 2.在Web Servcie中使用Sessio ...

  5. 转-Web Service中三种发送接受协议SOAP、http get、http post

    原文链接:web服务中三种发送接受协议SOAP/HTTP GET/HTTP POST 一.web服务中三种发送接受协议SOAP/HTTP GET/HTTP POST 在web服务中,有三种可供选择的发 ...

  6. 企业级SOA之路——在Web Service中使用HTTP和JMS

    原文:http://www.tibco.com/resources/solutions/soa/enterprise_class_soa_wp.pdf   概述     IT业界在早期有一种误解,认为 ...

  7. Web Service中的几个重要术语

    WSDL:web service definition language 直译:WebService定义语言 1.对应一种该类型的文件.WSDL 2.定义了Web Service的服务器与客户端应用交 ...

  8. Web Service中的XFire 传输List 自定义对象.

    我把这个创建的步骤和代码的贴出来,. 首先新建一个工程,取名就随便点啦..MyWebService,然后复制jar包到lib目录下, 创建包,建立接口..写一个javaBean的类, 以下是一个简单的 ...

  9. Dictionary(支持 XML 序列化),注意C#中原生的Dictionary类是无法进行Xml序列化的

    /// <summary> /// Dictionary(支持 XML 序列化) /// </summary> /// <typeparam name="TKe ...

随机推荐

  1. IDEA字体设置

    最近编码总是把","和"."搞错,字体实在是太小了,看不清,而且g的显示各个字体显示也是不一样,看的十分难受,果断换字体.分享一下在IDEA2017.2.5中如 ...

  2. 刻录DVD.Win7系统盘(U盘)

    ZC:Win7x86的U盘安装盘做好之后,U盘 里面会留有 引导信息,在以后不想要它(引导信息)的时候 该如果将它删掉?直接普通的格式化 能行吗? ZC:(20180423)发现,UltraISO制作 ...

  3. pg数据库表接口和数据导出

    导出命令 pg_dump -U postgres --inserts -t human_info > D:\human_info_backup.sql testdb 命令说明 pg_dump:是 ...

  4. 井眼轨迹的三次样条插值 (vs + QT + coin3d)

    井眼轨迹数据的测量值是离散的,根据某些测斜公式,我们可以计算出离散的三维的井眼轨迹坐标,但是真实的井眼轨迹是一条平滑的曲线,这就需要我们对测斜数据进行插值,使井眼轨迹变得平滑,我暂时决定使用三次样条进 ...

  5. 机器学习(二十七)— EM算法

    1.EM算法要解决的问题 如果使用基于最大似然估计的模型,模型中存在隐变量,就要用EM算法做参数估计. EM算法解决这个的思路是使用启发式的迭代方法,既然我们无法直接求出模型分布参数,那么我们可以先猜 ...

  6. 《Advanced Bash-scripting Guide》学习(九):备份最后一天所有修改的文件

    本文所选的例子来自于<Advanced Bash-scripting Gudie>一书,译者 杨春敏 黄毅 Example 3-4. 备份最后一天所有修改的文件 #!/bin/bash # ...

  7. python中sort()方法的cmp参数

    <python基础编程>里有讲到一段高级排序: “如果希望元素能按照特定的方式进行排序(而不是sort函数默认的方式,即根据python的默认排序规则按升序排列元素,第5章内对此进行讲解) ...

  8. spring MVC HandlerInterceptorAdapter

    SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理.比如通过它来进行权限验证,或者是来判断用户是否登陆,或者是像12306 那 ...

  9. C#中的索引器的简单理解和用法

    索引器是一种特殊的类成员,它能够让对象以类似数组的方式来存取,使程序看起来更为直观,更容易编写. 1.索引器的定义 C#中的类成员可以是任意类型,包括数组和集合.当一个类包含了数组和集合成员时,索引器 ...

  10. 基于Seajs的可控台球碰撞游戏

    前言 不记得哪个黑色星期五,贪吃鱼基本完工的时候,产品突然增加需求,要求金币扔出去后不消失,互相可碰撞,其最终结果还要由服务器控制(没错,至今做的所有游戏都有幕后黑手,=W=). 对于碰撞以前只写过一 ...