zoukankan      html  css  js  c++  java
  • 问题:不支持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法雖有其他缺點,但內建支援的特點,在力求簡單的場合裡,倒也值得納入考量吧!

  • 相关阅读:
    VBA 的编写与执行
    C# eBook
    【转】Winfrom datagridview 打印
    jquery循序渐渐1
    C# 数据库备份及还原
    Asp.net调用RAR压缩 解压文件
    SQL Server 2005下的分页SQL
    优秀文档收藏
    动态传入“表名,字段名,字段类型,默认值”四个字符串,根据新的字段名称和类型来创表表结构
    一句话搞定生日提示
  • 原文地址:https://www.cnblogs.com/longphui/p/4923354.html
Copyright © 2011-2022 走看看