使用Web Service

作为Web Service 的客户端,为了使用Web Service 有以下几个问题需要解决:

  1. 在设计阶段,需要依据WSDL对Web Service的描述来决定该使用什么方法,如何使用等信息.
  2. 在运行时阶段,需要封装方法的参数信息为Soap格式,并需要处理方法返回的Soap文档
  3. 在客户端与服务端通信的时候,由于Web Service一般是基于Http协议,需要在客户端创建代码以达到与服务端进行http的通信.

这些工作相信对于很多程序来说是复杂与繁琐的(当然也包括我:) ) ,还好微软提供了一个工具来完成这个事情,那就是WSDL这个命令行工具.

此工具会依据WSDL规范的信息来生成一个代理类,由于WSDL规范已经描述了Web Service 中的接口信息,并且描述了如何通信,关于WSDL的格式会在后面的文章有个详细的描述.客户端只需要与这个代理类打交道就行了,一切复杂繁琐的事情都交给代理类来完成.

这个工具可以直接在visual studio 提供的command prompt中使用 ,基本语法为:

wsdl http://localhost/MySecondWebService.asmx ,这样写会在WSDL所在的目录生成一个c#的代理类文件.如果你想生成vb.net语言的需要这样写:

wsdl /language:VB http://localhost/MySecondWebService.asmx

上述情况生成的文件名与WebService特性中指定的name名一样而不是与类名一样.想指定文件名语法如下:

wsdl /out:MySecondWebService.cs http://localhost/MySecondWebService.asmx

如果想给生成的类文件加上命名空间,语法为

wsdl /out:MySecondWebService.cs /namespace:David.WSTest http://localhost/MySecondWebService.asmx

详细的参数可以wsdl/?查看.

之所以在这里说这个命令行工具,是因为有些程序需要在运行时依据WSDL规范动态生成代理类并编译,那么直接调用这个工具来帮助生成就是一个比较简单的实现.

另外一个生成代理类的方式是利用Visual Studio 2008 自带的向导来生成,在我的安装篇中有一点点介绍,这里就不截图了,博客园搞截图太麻烦了.只是需要说明的是利用向导生成的代理类,利用visual studio的帮助可以直接更新以对应修改之后的web service

相信大家都注意到了,在visual studio中开发web service的时候其端口是动态生成的,那如何保证客户端使用正确的Web Service 呢?或者进行产品发布时通常端口变为80端口了.自从Visual Studio 2005开始,这个web service 的url就已经开始存储在配置文件中了.节点如下面蓝色字体所示:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="localhost.EmployeesService"
value="http://localhost/WebServices1/EmployeesService.asmx"/>
</appSettings>

</configuration>

注:命令行工具可以通过指定appsettingurlkey这个参数来指定配置文件中key的名字

关于生成的代理类有二点需要说明一下.

  1. 代理类继承自System.Web.Services.Protocols.SoapHttpClientProtocol,此类中有些属性如Timeout,proxy(指定代理服务器用)比较有用.
  2. 生成的代理类的命名空间是客户端的命名空间在加上添加Web Service引用时添加的命名空间下.如客户端的命名空间为David.WSTestClient ,而添加引用时你指定的名字为First,那么生成的代理类的命名空间为David.WSTestClient.First.ProxyClassName

Web Service的完整使用的代码为(省略了命名空间,类的声明等代码片段)

using David.WSTestClient.First;

private void button_click(object sender,EventArgs args)

{

MySecondWS wsproxy = new MySecondWS();

string result = wsproxy.HelloWorld();

}

 

方法的异步调用 

 在添加Web Service引用的时候会生成方法的异步版本,正是有了这些异步版本才使得进行异步操作容易多了.由于这与委托的异步操作是一样的,就不做详细的解释,一般使用的代码如下:

 private void btnAsyncCall_Click(object sender, EventArgs e)

        {

            MySecondWS proxy = new MySecondWS();

            proxy.HelloWorldCompleted += new WSStudyClient.AsyncTest.HelloWorldCompletedEventHandler(proxy_HelloWorldCompleted);

            proxy.HelloWorldAsync();//立即返回,如果是winForm项目,此时的窗体仍然是响应的,用户可以拖动窗体,点击其他按钮等操作.

        }


        void proxy_HelloWorldCompleted(object sender, WSStudyClient.AsyncTest.HelloWorldCompletedEventArgs e)

        {

            MessageBox.Show(e.Result);

        } 

 相信看到上面的代码,大家都明白那是基于事件的,那么这个事件的引发是怎么回事呢?因为http是无状态的(现在的web 编程都是基于请求响应模型),服务端是不可能主动通知client所调用的方法已经完成了,真正的原因就是当客户端调用proxy.HelloWorldAsync()这个方法的时候,就立即返回,然后此代理类仍然会在一个空闲线程上等待服务端返回结果,只要结果一返回并反序列化后(返回的是xml数据)就引发了事件,这一切都是发生在客户端,并没有违反Http的情况.(毕竟微软也不是神)

 

 关于取消方法的执行

由于proxy.HelloWorldAsync() 还有一个重载版本的方法,需要一个参数,参数的类型为object,这个主要是用来标识一个异步调用方法,这样我们调用proxy.CancelAsync()方法时就可以知道要取消哪个方法的执行了.代码片段如下:

 MySecondWS proxy = new MySecondWS();

Guid id = Guid.NewGuid();

proxy.HelloWorldAsync(id);

//取消方法执行 

proxy.CancelAsync(id); 

关于异步调用有以下几点需要说明

1.上面的取消方法执行,仍然会引发方法执行已经完成的事件,所以这个时候对结果的处理就要小心一些(直接像上面的代码所示是不行,因为此时都没有结果)

2.异步调用并没有加快方法的执行速度.只不过客户端不用等待,可以干别的事情.

3.可以自己通过线程的方式也可以达到这样的效果,不一定非要用上面所讲的方式. 

 

还有一种情况,对于异步调用来讲是没有意义的,那就是服务端的方法标示为单向方法(也叫做引发即忘记 fire-and-forget method),客户端调用这种类型的方法时总是立即返回,所以异步的调用是没有意义的,单向方法的实现如下

[SoapDocumentMethod(OneWay=true)] 

[WebMethod()]

publi string HelloWorld(){...} 

这种方法有以下几个缺点就是没有返回数据给客户端即便是方法有返回值(直接在服务端执行就完了,所以返回类型为void就较适合),并且out,ref类型的参数也不会返回,如果代码发生了异常,客户端也没有办法知道. 

 

posted @ 2010-01-11 15:16  CodeWorker  阅读(417)  评论(0编辑  收藏  举报