WebService中使用自定義類的解決方法(5種)

weixin_33982670發表於2018-01-27

轉自:http://www.cnblogs.com/lxinxuan/archive/2007/05/24/758317.html

       Demo下載:http://files.cnblogs.com/lxinxuan/wa.rar
       最近一個專案要用到webservice呼叫業務層類,剛開始的時候遇到了一點小麻煩,經過這兩天的總結和實踐,終於總結出幾個比較常見的情況下的解決方法。
        不知道大家是怎麼解決,可能太簡單了,所以沒有覺得它是一個問題。反正我在部落格園中沒有搜尋到相關的帖子。
        說實話,以前並沒有真正開發過涉及webservice的專案,頂多也就是看看msdn,寫點小程式,當時並沒有發現問題,因為傳遞的引數和返回值都是簡單資料型別,所以並沒有發現本文提及的問題——使用自定義類。
         所謂自定義類,不知道我有沒有表達清楚,這裡指的就是petshop中的Model層實體類了。
         比如以下程式碼:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace Model
{
    [Serializable]
    public class Student
    {
        private string stuName;

        public Student()
        { }

        public string StuName
        {
            get { return this.stuName; }
            set { this.stuName = value; }
        }
    }
}


webservice傳遞的內容必須是可序列化的,不管是引數還是返回值。上面定義的實體類Student,在類定義之前標示了[Serializable],指明可序列化的。但當涉及到實體類集合的時候,如果使用IList<Student>來表示,就會抱錯,原因是IList是不可以序列化的,這種情況下,我們就可以使用System.Collections.ObjectModel.Collection<Student>來表示一個實體類集合。這裡給出了兩種可能出現的實體類和實體類集合,以下就開始說明各種解決方法:

1、把實體類集合,作為Object[]傳遞。
      這種情況下,我們必須使用webservice中的實體類,傳遞的是實體類集合對應的Object[]傳遞,WebService中方法的引數型別是ArrayList。
比如WebService中的方法是:

[XmlInclude(typeof(Student))]
        [WebMethod]
        public string HelloStus(ArrayList stuList)
        {
            BLL.Class1 cls = new BLL.Class1();
            return cls.GetName(stuList);
        }

別漏了[XmlInclude(typeof(Student))]這一行,不然在表現層就引用不到WebService中的實體類了。
這個時候,在表現層新增web引用,表現層中的呼叫程式碼如下:(參考Demo中的button1_Click()方法)

/// <summary>
        /// 必須使用webservice中的實體類,傳遞實體類集合,作為Object[]傳遞,WebService中的引數型別是ArrayList,並提供一個將集合轉化為Object[]的公共類
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            string str = "";

            localhost.Student stuInfo1 = new localhost.Student();
            stuInfo1.StuName = "lxinxuan";
            localhost.Student stuInfo2 = new localhost.Student();
            stuInfo2.StuName = "www.cnblogs.com/lxinxuan";

            IList<localhost.Student> stuList = new List<localhost.Student>();
            stuList.Add(stuInfo1);
            stuList.Add(stuInfo2);

            object[] array = this.ConvertToArray<localhost.Student>(stuList);//這是一個將集合轉換為Objec[]的泛型方法
            str = ser.HelloStus(array);//傳遞Object[],返回值是StuName的值

            MessageBox.Show(str);
        }
//這是一個將集合轉換為Objec[]的泛型方法
 private object[] ConvertToArray<T>(IList<T> tList)
        {
            object[] array = new object[tList.Count];
            int i = 0;
            foreach (T t in tList)
            {
                array[i] = t;
                i++;
            }
            return array;
        }


2、傳遞單個實體類,使用WebService中的實體類
這種情況下,可以看作是情況1的特例——只有一個元素的陣列。
當然,這種情況下我們可以換一種做法——使用WebService中的實體類。
先看webservice中的程式碼:

[XmlInclude(typeof(Student))]
        [WebMethod]
        public string HelloStu(Student stuInfo)
        {
            return stuInfo.StuName;
        }

同樣必須新增這一行程式碼[XmlInclude(typeof(Student))]。
然後呼叫程式碼是:

 /// <summary>
        /// 傳遞單個實體類,使用WebService中的實體類
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            string str = "";
            localhost.Student stuInfo1 = new localhost.Student();//注意,這裡呼叫了webservice中的實體類,而不是Model中的實體類。否則出錯。
            stuInfo1.StuName = "lxinxuan";
            str = ser.HelloStu(stuInfo1);//傳遞webservice中的實體類
            MessageBox.Show(str);
        }


3、傳遞實體類構成的Collection。這是和情況1類似的情形,只是傳遞的型別不一樣。可以對照一下。
這種情況下,必須通過修改Reference.cs的程式碼,不過每次更新都要重新修改,而且必須每個類修改,比較麻煩!不推薦使用,這不知道是哪位仁兄想出來的方法,我也是看了人家的做法才總結出來的,不過能去修改Reference.cs的程式碼,已經說明鑽研精神了,鼓勵下。
同樣先給出webservice中方法的程式碼:

[WebMethod]
        public string HelloStusByList(Collection<Student> stuList)//這裡引數型別是Collection
        {
            BLL.Class1 cls = new BLL.Class1();
            return cls.GetName(stuList);
        }

方法的引數是Collection,在新增了webservice之後,Reference.cs中的對應方法的引數變成了student[],陣列!!webservice和陣列走得真近阿。。。這裡將Reference.cs中的方法HelloStusByList的引數型別student[]改為Collection<localhost.Student>,如下所示。
表示層呼叫程式碼:

/// <summary>
        /// 傳遞實體類構成的Collection,通過修改Reference.cs的程式碼,不過每次更新WebService之後都要重新修改,而且必須每個類修改,麻煩
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            string str = "";

            localhost.Student stuInfo1 = new localhost.Student();
            stuInfo1.StuName = "lxinxuan";
            localhost.Student stuInfo2 = new localhost.Student();
            stuInfo2.StuName = "www.cnblogs.com/lxinxuan";

            Collection<localhost.Student> stuList = new Collection<localhost.Student>();
            stuList.Add(stuInfo1);
            stuList.Add(stuInfo2);

            str = ser.HelloStusByList(stuList);//預設情況下,這裡HelloStusByList方法的引數是Student[],通過手動修改為Collection,就可以了

            MessageBox.Show(str);
        }


4、先將實體類集合序列化為表現為xml格式的string,然後在webservice中反序列化成Collection<>(注意:不可以是IList<>),然後再傳遞給業務層物件。
[2007-5-25修改:博友“程式碼亂了”提出,可以採用二進位制序列化。確實是的,這裡的xml序列化和binary序列化都是可以的,只是我為了除錯時跟蹤資訊方便,才用了xml序列化。這裡不再羅列出來。謝謝“程式碼亂了”]

[WebMethod]
        public string HelloStusByCollection(string sXml)
        {
            BLL.Class1 cls = new BLL.Class1();
            Collection<Student> stuList = cls.DeSerializerCollection<Student>(sXml, typeof(Collection<Student>));//先反序列化為Collection
            return cls.GetName(stuList);
        }

DeserializerCollection方法程式碼如下:

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sXml"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public Collection<T> DeSerializerCollection<T>(string sXml, Type type)
        {
            XmlReader reader = XmlReader.Create(new StringReader(sXml));
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(type);
           
            object obj = serializer.Deserialize(reader);
            return (Collection<T>)obj;
        }


表現層呼叫程式碼如下:

/// <summary>
        /// 先將實體類集合序列化為string,然後在webservice中反序列化成Collection<>,然後再傳遞給業務層物件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button4_Click(object sender, EventArgs e)
        {
            string str = "";

            Student stuInfo1 = new Student();
            stuInfo1.StuName = "lxinxuan";
            Student stuInfo2 = new Student();
            stuInfo2.StuName = "www.cnblogs.com/lxinxuan";

            Collection<Student> stuList = new Collection<Student>();
            stuList.Add(stuInfo1);
            stuList.Add(stuInfo2);

            string stuString = this.Serializer<Collection<Student>>(stuList);//先序列化為xml檔案格式的string
            str = ser.HelloStusByCollection(stuString);
            MessageBox.Show(str);
        }

Serialize方法程式碼如下:

/// <summary>
        /// 實體類集合序列化為字串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objToXml"></param>
        /// <returns></returns>
        public string Serializer<T>(T objToXml)
        {
            System.IO.StringWriter writer = new System.IO.StringWriter();
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(objToXml.GetType());
            serializer.Serialize(writer, objToXml);
            return writer.GetStringBuilder().ToString();
        }


5、這種情況就是情況4的特例,序列化一個實體類並傳遞,方法類似,就不寫出來,參見Demo程式碼。

大概就是這些了,當然傳遞DataSet是最傳統最好的辦法了,呵呵~

相關文章