问题:不支持Dictionary;结果:在Web Service中傳送Dictionary

在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法雖有其他缺點,但內建支援的特點,在力求簡單的場合裡,倒也值得納入考量吧!

时间: 2024-08-06 18:38:29

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

在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; } 天不從人願,以上的寫法會

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

原文:ASP.NET Web Service中使用Session 及 Session丢失解决方法 续 1.关于Session丢失问题的说明汇总,参考这里 2.在Web Servcie中使用Session,需要对Web Method做如下处理 [WebMethod(EnableSession = true)]public void usingSession(){    Session["Name"] = "Name";} 如果不加EnableSession = tru

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

Web Service 中返回DataSet结果的几种方法: 1)直接返回DataSet对象    特点:通常组件化的处理机制,不加任何修饰及处理:    优点:代码精减.易于处理,小数据量处理较快:    缺点:大数据量的传递处理慢,消耗网络资源:    建议:当应用系统在内网.专网(局域网)的应用时,或外网(广域网)且数据量在KB级时的应用时,采用此种模式. 2)返回DataSet对象用Binary序列化后的字节数组    特点:字节数组流的处理模式:    优点:易于处理,可以中文内容起到

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

原文链接:web服务中三种发送接受协议SOAP/HTTP GET/HTTP POST 一.web服务中三种发送接受协议SOAP/HTTP GET/HTTP POST 在web服务中,有三种可供选择的发送和接受信息的协议:SOAP,HTTP GET,HTTP POST,但是SOAP支持的数据类型更为广泛 SOAP=RPC+HTTP+XML SOAP简单的理解,就是这样的一个开放协议SOAP=RPC+HTTP+XML:采用HTTP作为底层通讯协议:RPC作为一致性的调用途径,XML作为数据传送的格式

Web Service中的几个重要术语

WSDL:web service definition language 直译:WebService定义语言 1.对应一种该类型的文件.WSDL 2.定义了Web Service的服务器与客户端应用交互船度请求和响应数据的格式和方式 3.一个web service对应一咯唯一的wsdl文档 SOAP:simple object access protocal 直译:简单对象访问协议 1.一种更简单的.基于HTTP和xml的协议,用于在WEB上交换结构化的数据 2.soap消息:请求消息和响应消息

host不能访问虚拟机内web service中踩到的坑--2017年5月3日

host访问vm中的web service,一直显示不能连接 关闭host和vm中的防火墙,查看host中端口占用情况,都无果 最后发现启动服务的方式错了: python manage.py runserver 0.0.0.0:port 监听所有ip python manage.py runserver 只能在本地访问

ASP.NET支持用Menu显示web.sitemap中定义好的网站链接 【转载】

在页面上添加一个SiteMapDataSource,  SiteMapDataSource会使用web.config中指定的default siteMap provider读取web.sitemap的内容. 再把SiteMapDataSource作为数据源指定给Menu控件就搞定了.整个过程不用写一行代码ASP.NET还提供了对权限控制和Localization的支持, 在web.config中设定sitemap provider是否对siteMapNode进行过滤: <siteMap defa

Web Service学习笔记

Web Service概述 Web Service的定义 W3C组织对其的定义例如以下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计.Web Service服务通常被定义为一组模块化的API,它们可以通过网络进行调用,来运行远程系统的请求服务. 这里我们从一个程序猿的视角来观察web service.在传统的程序编码中,存在这各种的函数方法调用.通常,我们知道一个程序模块M中的方法A,向其发出调用请求,并传入A方法须要的參数P,方法A运行完毕后,返回处理结果R.这样的函数或方法调用

Web Service学习笔记(webservice、soap、wsdl、jws详细分析) (转)

Web Service概述 Web Service的定义 W3C组织对其的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计.Web Service服务通常被定义为一组模块化的API,它们可以通过网络进行调用,来执行远程系统的请求服务. 这里我们从一个程序员的视角来观察web service.在传统的程序编码中,存在这各种的函数方法调用.通常,我们知道一个程序模块M中的方法A,向其发出调用请求,并传入A方法需要的参数P,方法A执行完毕后,返回处理结果R.这种函数或方法调用通常发