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
{
![](https://i-blog.csdnimg.cn/blog_migrate/b6395f47c62a02353a784dc00a761649.gif)
[Serializable]
public class Student
{
private string stuName;
public Student()
{ }
public string StuName
{
get { return this.stuName; }
set { this.stuName = value; }
![](https://i-blog.csdnimg.cn/blog_migrate/ec3bdd5f95ed074ec9a3408a76c1f394.gif)
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a02153f770540e0e6de1f026d45d8ca.gif)
}
![](https://i-blog.csdnimg.cn/blog_migrate/711bf6535b883075d9283a02306429ef.gif)
}
webservice传递的内容必须是可序列化的,不管是参数还是返回值。上面定义的实体类Student,在类定义之前标示了[Serializable],指明可序列化的。但当涉及到实体类集合的时候,如果使用IList<Student>来表示,就会抱错,原因是IList是不可以序列化的,这种情况下,我们就可以使用System.Collections.ObjectModel.Collection<Student>来表示一个实体类集合。这里给出了两种可能出现的实体类和实体类集合,以下就开始说明各种解决方法:
1、把实体类集合,作为Object[]传递。这种情况下,我们必须使用webservice中的实体类,传递的是实体类集合对应的Object[]传递,WebService中方法的参数类型是ArrayList。
比如WebService中的方法是:
[XmlInclude(
typeof
(Student))]
![](https://i-blog.csdnimg.cn/blog_migrate/6a043a26c66fe6409384fbd4ee397acc.gif)
[WebMethod]
public
string
HelloStus(ArrayList stuList)
{
![](https://i-blog.csdnimg.cn/blog_migrate/174d6006febef62d1785f4cf5d3909bb.gif)
BLL.Class1 cls
= new BLL.Class1();
return cls.GetName(stuList);
![](https://i-blog.csdnimg.cn/blog_migrate/4a9e64e112e2e732810d81c6a91dc466.gif)
}
别漏了[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 = "";
![](https://i-blog.csdnimg.cn/blog_migrate/931c6141a9c89f4cdcdcc79627b623b0.gif)
localhost.Student stuInfo1
= new localhost.Student();
![](https://i-blog.csdnimg.cn/blog_migrate/ff0fb1e26727ff3a2bf62ad73489d370.gif)
stuInfo1.StuName
= "lxinxuan";
![](https://i-blog.csdnimg.cn/blog_migrate/b4fd73ea1805e17ee979b1477f11cd1d.gif)
localhost.Student stuInfo2
= new localhost.Student();
![](https://i-blog.csdnimg.cn/blog_migrate/a59fb953cb47ded08e849735446c2951.gif)
stuInfo2.StuName
= "www.cnblogs.com/lxinxuan";
![](https://i-blog.csdnimg.cn/blog_migrate/ef7a52b7b8c04832e14cac690d2400ea.gif)
IList
<localhost.Student> stuList = new List<localhost.Student>();
![](https://i-blog.csdnimg.cn/blog_migrate/f0d5c921737bcbf41a6047b7464cdbfb.gif)
stuList.Add(stuInfo1);
![](https://i-blog.csdnimg.cn/blog_migrate/72d699f2b0a22915543f1be9ae34c08d.gif)
stuList.Add(stuInfo2);
object[] array = this.ConvertToArray<localhost.Student>(stuList);//这是一个将集合转换为Objec[]的泛型方法
str = ser.HelloStus(array);//传递Object[],返回值是StuName的值
![](https://i-blog.csdnimg.cn/blog_migrate/38f587ffbb20ecea49a4c8c16bbc15c9.gif)
MessageBox.Show(str);
![](https://i-blog.csdnimg.cn/blog_migrate/ac2b3dc0e0d3211de6e47d99f2f60684.gif)
}
//
这是一个将集合转换为Objec[]的泛型方法
private
object
[] ConvertToArray
<
T
>
(IList
<
T
>
tList)
{
object[] array = new object[tList.Count];
int i = 0;
foreach (T t in tList)
{
![](https://i-blog.csdnimg.cn/blog_migrate/f7d8ea7fea1239c474e07c2fdc0c6c97.gif)
array[i]
= t;
![](https://i-blog.csdnimg.cn/blog_migrate/cc18d0dc9a152433fe0882239e49d776.gif)
i
++;
![](https://i-blog.csdnimg.cn/blog_migrate/4bdc99eb8328b74ef20ff813031d5121.gif)
}
return array;
![](https://i-blog.csdnimg.cn/blog_migrate/f8ca0cd7aa80476518e1eb24343fa6fd.gif)
}
2、传递单个实体类,使用WebService中的实体类这种情况下,可以看作是情况1的特例——只有一个元素的数组。当然,这种情况下我们可以换一种做法——使用WebService中的实体类。先看webservice中的代码:
[XmlInclude(
typeof
(Student))]
![](https://i-blog.csdnimg.cn/blog_migrate/6e599e9ad221bf9d3d479ba760448e95.gif)
[WebMethod]
public
string
HelloStu(Student stuInfo)
{
return stuInfo.StuName;
![](https://i-blog.csdnimg.cn/blog_migrate/f6ca5001f6d8711a003a3a41334b2787.gif)
}
同样必须添加这一行代码[XmlInclude(typeof(Student))]。
然后调用代码是:
/// <summary>
/// 传递单个实体类,使用WebService中的实体类
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private
void
button2_Click(
object
sender, EventArgs e)
{
string str = "";
![](https://i-blog.csdnimg.cn/blog_migrate/1943c64891a09e2c8a5bd50c884fbec4.gif)
localhost.Student stuInfo1
= new localhost.Student();//注意,这里调用了webservice中的实体类,而不是Model中的实体类。否则出错。
![](https://i-blog.csdnimg.cn/blog_migrate/7e02bb0e7c7737418e18b0c004fde213.gif)
stuInfo1.StuName
= "lxinxuan";
![](https://i-blog.csdnimg.cn/blog_migrate/a07a0df9127ed198ae44498ac30bcd9a.gif)
str
= ser.HelloStu(stuInfo1);
![](https://i-blog.csdnimg.cn/blog_migrate/912d81578173a88d55efa596765d7f92.gif)
//传递webservice中的实体类
![](https://i-blog.csdnimg.cn/blog_migrate/d83c7fcc5342a79c83cd3f1d47604e39.gif)
MessageBox.Show(str);
![](https://i-blog.csdnimg.cn/blog_migrate/306f853effa0be0b26bc1b0f5ff0cec9.gif)
}
3、传递实体类构成的Collection。这是和情况1类似的情形,只是传递的类型不一样。可以对照一下。这种情况下,必须通过修改Reference.cs的代码,不过每次更新都要重新修改,而且必须每个类修改,比较麻烦!不推荐使用,这不知道是哪位仁兄想出来的方法,我也是看了人家的做法才总结出来的,不过能去修改Reference.cs的代码,已经说明钻研精神了,鼓励下。同样先给出webservice中方法的代码:
[WebMethod]
public
string
HelloStusByList(Collection
<
Student
>
stuList)
//
这里参数类型是Collection
{
![](https://i-blog.csdnimg.cn/blog_migrate/aba0dad666b7c6c075462e7d8144acd6.gif)
BLL.Class1 cls
= new BLL.Class1();
return cls.GetName(stuList);
![](https://i-blog.csdnimg.cn/blog_migrate/713af0e70e4e1c8893c41a0b4f80e04b.gif)
}
方法的参数是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 = "";
![](https://i-blog.csdnimg.cn/blog_migrate/5e85880368544809b9f127367eac7308.gif)
localhost.Student stuInfo1
= new localhost.Student();
![](https://i-blog.csdnimg.cn/blog_migrate/2fcfc46fe8a283bcc2e7dbcda180f85e.gif)
stuInfo1.StuName
= "lxinxuan";
![](https://i-blog.csdnimg.cn/blog_migrate/f929e062fc80c1cd0618ec687b0840a5.gif)
localhost.Student stuInfo2
= new localhost.Student();
![](https://i-blog.csdnimg.cn/blog_migrate/858179e3971d835cce9e2123d891566b.gif)
stuInfo2.StuName
= "www.cnblogs.com/lxinxuan";
![](https://i-blog.csdnimg.cn/blog_migrate/e44361333fd79b91472d38451b6d06a3.gif)
Collection
<localhost.Student> stuList = new Collection<localhost.Student>();
![](https://i-blog.csdnimg.cn/blog_migrate/e94d92b2229a63d1a950c896c014b0ac.gif)
stuList.Add(stuInfo1);
![](https://i-blog.csdnimg.cn/blog_migrate/99be81787ac530dbaf78a3f5ec4eda2d.gif)
stuList.Add(stuInfo2);
![](https://i-blog.csdnimg.cn/blog_migrate/7eda86e27f95a816a28905d4be9305df.gif)
str
= ser.HelloStusByList(stuList);//默认情况下,这里HelloStusByList方法的参数是Student[],通过手动修改为Collection,就可以了
![](https://i-blog.csdnimg.cn/blog_migrate/eb319c9b029c6d954d1fb968532b751b.gif)
MessageBox.Show(str);
![](https://i-blog.csdnimg.cn/blog_migrate/e97472d0332ab030b2b60d01d4725b11.gif)
}
4、先将实体类集合序列化为表现为xml格式的string,然后在webservice中反序列化成Collection<>(注意:不可以是IList<>),然后再传递给业务层对象。[2007-5-25修改:博友“代码乱了”提出,可以采用二进制序列化。确实是的,这里的xml序列化和binary序列化都是可以的,只是我为了调试时跟踪信息方便,才用了xml序列化。这里不再罗列出来。谢谢“代码乱了”]
[WebMethod]
public
string
HelloStusByCollection(
string
sXml)
{
![](https://i-blog.csdnimg.cn/blog_migrate/ed8f5c4592b836cb9ca8ecaf806a5670.gif)
BLL.Class1 cls
= new BLL.Class1();
![](https://i-blog.csdnimg.cn/blog_migrate/a6fc24d0eae94c7458e59f04e3c9abd2.gif)
Collection
<Student> stuList = cls.DeSerializerCollection<Student>(sXml, typeof(Collection<Student>));//先反序列化为Collection
return cls.GetName(stuList);
![](https://i-blog.csdnimg.cn/blog_migrate/4ba133d650609314d81907df55836310.gif)
}
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)
{
![](https://i-blog.csdnimg.cn/blog_migrate/0d686115699539946cfe0fa0e6862b67.gif)
XmlReader reader
= XmlReader.Create(new StringReader(sXml));
![](https://i-blog.csdnimg.cn/blog_migrate/cf97ad3103bab249714ee09eaaaa11bc.gif)
System.Xml.Serialization.XmlSerializer serializer
= new System.Xml.Serialization.XmlSerializer(type);
object obj = serializer.Deserialize(reader);
return (Collection<T>)obj;
![](https://i-blog.csdnimg.cn/blog_migrate/d8ee361c95463f75648515c38c942885.gif)
}
表现层调用代码如下:
/// <summary>
/// 先将实体类集合序列化为string,然后在webservice中反序列化成Collection<>,然后再传递给业务层对象
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private
void
button4_Click(
object
sender, EventArgs e)
{
string str = "";
![](https://i-blog.csdnimg.cn/blog_migrate/14553edb6229a2e143f6cf1e139c54ee.gif)
Student stuInfo1
= new Student();
![](https://i-blog.csdnimg.cn/blog_migrate/10b76ce02fa9910a79454357ce31397c.gif)
stuInfo1.StuName
= "lxinxuan";
![](https://i-blog.csdnimg.cn/blog_migrate/597e485681562799ee9c05b08ea76c8f.gif)
Student stuInfo2
= new Student();
![](https://i-blog.csdnimg.cn/blog_migrate/15c42eb4fe3bd66e34e8a99e913d5cd0.gif)
stuInfo2.StuName
= "www.cnblogs.com/lxinxuan";
![](https://i-blog.csdnimg.cn/blog_migrate/8c6eacfec946ac5082e825f0cff22383.gif)
Collection
<Student> stuList = new Collection<Student>();
![](https://i-blog.csdnimg.cn/blog_migrate/485318ca1ab43b36dc64fad2cbcc2abf.gif)
stuList.Add(stuInfo1);
![](https://i-blog.csdnimg.cn/blog_migrate/e87a07564e7ba0cf544ecac0e8fb21d2.gif)
stuList.Add(stuInfo2);
string stuString = this.Serializer<Collection<Student>>(stuList);//先序列化为xml文件格式的string
![](https://i-blog.csdnimg.cn/blog_migrate/979ffd3522219bae1283239062200419.gif)
str
= ser.HelloStusByCollection(stuString);
![](https://i-blog.csdnimg.cn/blog_migrate/300f6c7f3c9a120bf78d1a7fd1d39bc6.gif)
MessageBox.Show(str);
![](https://i-blog.csdnimg.cn/blog_migrate/2b32b66c230cbabd36547b75e21a502a.gif)
}
Serialize方法代码如下:
/// <summary>
/// 实体类集合序列化为字符串
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="objToXml"></param>
/// <returns></returns>
public
string
Serializer
<
T
>
(T objToXml)
{
![](https://i-blog.csdnimg.cn/blog_migrate/7633251b538ffe5ff284f785829237e9.gif)
System.IO.StringWriter writer
= new System.IO.StringWriter();
![](https://i-blog.csdnimg.cn/blog_migrate/7a61d66366e75fa712a65ceaa8aa39d4.gif)
System.Xml.Serialization.XmlSerializer serializer
= new System.Xml.Serialization.XmlSerializer(objToXml.GetType());
![](https://i-blog.csdnimg.cn/blog_migrate/12920b1db8d7b16640964fbb459930c7.gif)
serializer.Serialize(writer, objToXml);
return writer.GetStringBuilder().ToString();
![](https://i-blog.csdnimg.cn/blog_migrate/0ff1147051edb0108e81ae89119b397a.gif)
}
5、这种情况就是情况4的特例,序列化一个实体类并传递,方法类似,就不写出来,参见Demo代码。大概就是这些了,当然传递DataSet是最传统最好的办法了,呵呵~