惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
腾讯CDC
阮一峰的网络日志
阮一峰的网络日志
GbyAI
GbyAI
B
Blog RSS Feed
Engineering at Meta
Engineering at Meta
Google DeepMind News
Google DeepMind News
MyScale Blog
MyScale Blog
Last Week in AI
Last Week in AI
F
Fortinet All Blogs
云风的 BLOG
云风的 BLOG
N
Netflix TechBlog - Medium
G
Google Developers Blog
博客园_首页
有赞技术团队
有赞技术团队
V
V2EX
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
MongoDB | Blog
MongoDB | Blog
H
Help Net Security
aimingoo的专栏
aimingoo的专栏
月光博客
月光博客
Hugging Face - Blog
Hugging Face - Blog
The GitHub Blog
The GitHub Blog
S
SegmentFault 最新的问题

博客园 - 随风而逝

现况调查的方法及种类 GDP 母版页运行机制 VS2005调试问题解决方案集锦 QQ技术攻略-原来隐藏着这么多秘密 英语谚语500句 房产证的作用 五证 10 signs that you’re not cut out to be an IT manager 重新飞翔 你还想熬夜吗? 使用ADOMD.NET建立与Analysis Services的连接 关于MS数据仓库备份 微软的Analysis Services无法连接 如何使用ADOMD执行OLAP操作 表中某列被修改后触发器SQL例子 如何调试触发器 sql server 2005中的DDL触发器 SQL语句备忘录
WebService中使用自定义类的解决方法(5种)
随风而逝 · 2008-03-14 · via 博客园 - 随风而逝

原文地址:http://www.cnblogs.com/lxinxuan/archive/2007/05/24/758317.html
  Demo下载:https://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<>),然后再传递给业务层对象。

[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是最传统最好的办法了,呵呵~