代码改变世界

把Web Services生成服务器端C#、VB。或者接口

2015-05-09 23:21  糯米粥  阅读(1780)  评论(0编辑  收藏  举报

什么是Web Services?

  • Web Services 是应用程序组件
  • Web Services 使用开放协议进行通信
  • Web Services 是独立的(self-contained)并可自我描述
  • Web Services 可通过使用UDDI来发现
  • Web Services 可被其他应用程序使用
  • XML 是 Web Services 的基础

它如何工作?

  基础的 Web Services 平台是 XML + HTTP。

  HTTP 协议是最常用的因特网协议。

  XML 提供了一种可用于不同的平台和编程语言之间的语言。

Web services 平台的元素:

  • SOAP (简易对象访问协议)
  • UDDI (通用描述、发现及整合)
  • WSDL (Web services 描述语言)

 此文主要讲。通过Web Services 的WSDL生成C#代码

WSDL(网络服务描述语言,Web Services Description Language)是一门基于 XML 的语言,用于描述 Web Services 以及如何对它们进行访问。

首先来创建一个简单的服务,创建一个空Web应用程序,右键添加新建项,选择web服务,根据自己的需求命名

 

创建成功了。打开服务,生成了默认的文件代码

 

首先啥都不管,先运行看看,

DataInfo.asmx文件跟aspx文件一样,可以直接选中。右键在浏览器中查看

自此。你就看到了一个最简单的服务界面

 

 

这样你把这个服务发布到服务器。客户端就可以调用了。

现在手动调用试试,单击 "HelloWorld"

 

现在来尝试代码调用。把DataInfo.asmx服务发布到IIS。就好比别人发布了Web Services,现在我来调用

既然是测试。我就不用打开电脑的IIS了。用一卡西尼服务器即可。就是这个:CassiniDev4

这里提供一个下载地址:http://cassinidev.codeplex.com/

 

全路径就是这个:http://localhost:32768/DataInfo.asmx。在url地址栏打开就能看到

那么地址有了。在项目中就可以引用这个服务。

为了测试。这里在服务新增一个方法,返回两个数的和:Add(int x, int y)

 1 /// <summary>
 2         /// 返回两个数的和
 3         /// </summary>
 4         /// <param name="x"></param>
 5         /// <param name="y"></param>
 6         /// <returns></returns>
 7         [WebMethod(Description = "返回两数的和")]
 8         public int Add(int x, int y)
 9         {
10             return x + y;
11         }

 

方法名称上面添加WebMethod特性后。才能暴露在客户端,也就是说可以从远程Web客户端调用该方法

Description是对该方法的描述信息,会显示在客户端。添加完成,保存,F6重新生成代码。刷新浏览器你可以看到代码已经更新

好了。目前为止。服务已经配置好。并且已经发布。供别人免费使用。当有需要计算两个数之和的。就可以调用该服务

现在编写一个测试代码。创建一个项目。右键引用。选择添加服务引用

 

输入服务地址,命名。单击确定即可。当然你也可以看看该服务提供了那些方法。单击 "发现"

 

 

单击确定后。你发现。项目中已经生成了对该服务的引用

 

现在来编码调用里面的Add方法。创建一个页面。输入以下代码

1 protected void Page_Load(object sender, EventArgs e)
2         {
3             GetInfo.DataInfoSoapClient client = new GetInfo.DataInfoSoapClient();
4             int result = client.Add(9, 10);
5             Response.Write(result);
6         }

 

 

运行项目。成功的得到值为:19

那你有没有想过。当添加服务的引用后。内部都做了些什么。为什么添加以后就可以调用了呢?

把光标定位到Add方法。按F12转到方法的定义。

可以看到。其实已经生成了服务端的代码。

那这个代码在哪里呢。你根据项目的层次结构。

到项目的路径中看一看

 

打开Reference.cs 类。你会发现。里面生成了服务器代码。是自动生成的。别问我怎么知道的。它告诉我的:)

其实引用服务后,就生成服务的客户端代理类

 

哪天那个发布服务的人。一不小心。把Add方法的 "+" 改成了 "*",

1  [WebMethod(Description = "返回两数的和")]
2         public int Add(int x, int y)
3         {
4             return x * y;
5         }

 

客户端也会相应的更新,这就是一个同步更新

 

你也会发现。web.config里面有对服务的引用,

 

<?xml version="1.0"?>
<configuration>

    <system.web>
        <compilation debug="true" targetFramework="4.0" />
    </system.web>

    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="DataInfoSoap" />
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:9213/DataInfo.asmx" binding="basicHttpBinding"
                bindingConfiguration="DataInfoSoap" contract="GetInfo.DataInfoSoap"
                name="DataInfoSoap" />
        </client>
    </system.serviceModel>
</configuration>

 

 

来分析下<system.serviceModel>.... </system.serviceModel>节点的含义

 <!--此配置节包含所有 Windows Communication Foundation (WCF) ServiceModel 配置元素。-->
    <system.serviceModel>
      <!-- 此节包含标准绑定和自定义绑定的集合。 每一项均由其唯一的 name 进行标识。 服务通过用 name 与绑定进行链接来使用绑定。 -->
        <bindings>
            <!--绑定配置-->
            <basicHttpBinding>
                <!--每一项均由其唯一的 name 进行标识-->
                <binding name="DataInfoSoap" />
            </basicHttpBinding>
        </bindings>
      <!--此节包含客户端用来连接到服务的终结点的列表。-->
        <client>
          <!--终结点配置-->
            <endpoint address="http://localhost:9213/DataInfo.asmx" binding="basicHttpBinding"
                bindingConfiguration="DataInfoSoap" contract="GetInfo.DataInfoSoap"
                name="DataInfoSoap" />
        </client>
    </system.serviceModel>

 

详情:https://msdn.microsoft.com/zh-cn/library/ms731354

 

既然有人提供服务。也就会有人使用服务,

网上有很多对外公开的服务,比如:

获取天气的服务:http://www.webxml.com.cn/WebServices/WeatherWS.asmx

 

 

 

 

 

腾讯QQ查询状态http://webservice.webxml.com.cn/webservices/qqOnlineWebService.asmx

这些都是人家提供好了的。你只要直接在项目中引用。就像我上面的那样,在项目中引用其服务即可。因为这些是公共的。私有的另当别论。

但你有没有想过,如果你跟别人协同开发项目的时候。一个提供web服务,一个使用web服务。一个已经实现功能的WebService会发布自己的WSDL文件并不会发布到自己的服务器。那怎么办呢?

首先看看什么是WSDL?

WSDL(网络服务描述语言,Web Services Description Language)是一门基于 XML 的语言,用于描述 Web Services 以及如何对它们进行访问。

在服务后面加上wsdl

http://localhost:32768/DataInfo.asmx?wsdl。就可以得到当前服务的wsdl文件

然后把这个页面保存。保存为.wsdl文件即可,比如我保存在路径:

其实这样你依然可以在项目中添加该服务,地址为该路径即可

 

这样同样可以生成服务端C#代码,还有一种简单的方法。

使用VS2010提供的工具wsdl.exe由WSDL文件生成cs文件

 

 

看到界面:

 

 

 

输入wsdl回车,查看介绍

 

 

来分析下几个常用的命令:

默认为C#语言:

 

生成代码命令:

 

生成接口命令:

 

wsdl用法:

 

好了。现在来生成一个C#代码看看

 1:根据url路径生成代码,个人感觉没什么实际意义

来看看这条命令

wsdl是命令开始

/o:是开始输出

/o:后面是服务地址

生成的代码默认路径在

 

 

2:根据本地wsdl文件生成代码。如果上面的生成目录想根据自己来定义话。可以这样在 命令/o: 带上位置

 

从图片的标记可以看出来。已经成功了

来看看生成后的代码:

  1 //------------------------------------------------------------------------------
  2 // <auto-generated>
  3 //     此代码由工具生成。
  4 //     运行时版本:4.0.30319.18444
  5 //
  6 //     对此文件的更改可能会导致不正确的行为,并且如果
  7 //     重新生成代码,这些更改将会丢失。
  8 // </auto-generated>
  9 //------------------------------------------------------------------------------
 10 
 11 using System;
 12 using System.ComponentModel;
 13 using System.Diagnostics;
 14 using System.Web.Services;
 15 using System.Web.Services.Protocols;
 16 using System.Xml.Serialization;
 17 
 18 // 
 19 // 此源代码由 wsdl 自动生成, Version=4.0.30319.1。
 20 // 
 21 
 22 
 23 /// <remarks/>
 24 [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
 25 [System.Diagnostics.DebuggerStepThroughAttribute()]
 26 [System.ComponentModel.DesignerCategoryAttribute("code")]
 27 [System.Web.Services.WebServiceBindingAttribute(Name="DataInfoSoap", Namespace="http://tempuri.org/")]
 28 public partial class DataInfo : System.Web.Services.Protocols.SoapHttpClientProtocol {
 29     
 30     private System.Threading.SendOrPostCallback HelloWorldOperationCompleted;
 31     
 32     private System.Threading.SendOrPostCallback AddOperationCompleted;
 33     
 34     /// <remarks/>
 35     public DataInfo() {
 36         this.Url = "http://localhost:32768/DataInfo.asmx";
 37     }
 38     
 39     /// <remarks/>
 40     public event HelloWorldCompletedEventHandler HelloWorldCompleted;
 41     
 42     /// <remarks/>
 43     public event AddCompletedEventHandler AddCompleted;
 44     
 45     /// <remarks/>
 46     [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/HelloWorld", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
 47     public string HelloWorld() {
 48         object[] results = this.Invoke("HelloWorld", new object[0]);
 49         return ((string)(results[0]));
 50     }
 51     
 52     /// <remarks/>
 53     public System.IAsyncResult BeginHelloWorld(System.AsyncCallback callback, object asyncState) {
 54         return this.BeginInvoke("HelloWorld", new object[0], callback, asyncState);
 55     }
 56     
 57     /// <remarks/>
 58     public string EndHelloWorld(System.IAsyncResult asyncResult) {
 59         object[] results = this.EndInvoke(asyncResult);
 60         return ((string)(results[0]));
 61     }
 62     
 63     /// <remarks/>
 64     public void HelloWorldAsync() {
 65         this.HelloWorldAsync(null);
 66     }
 67     
 68     /// <remarks/>
 69     public void HelloWorldAsync(object userState) {
 70         if ((this.HelloWorldOperationCompleted == null)) {
 71             this.HelloWorldOperationCompleted = new System.Threading.SendOrPostCallback(this.OnHelloWorldOperationCompleted);
 72         }
 73         this.InvokeAsync("HelloWorld", new object[0], this.HelloWorldOperationCompleted, userState);
 74     }
 75     
 76     private void OnHelloWorldOperationCompleted(object arg) {
 77         if ((this.HelloWorldCompleted != null)) {
 78             System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
 79             this.HelloWorldCompleted(this, new HelloWorldCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
 80         }
 81     }
 82     
 83     /// <remarks/>
 84     [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/Add", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
 85     public int Add(int x, int y) {
 86         object[] results = this.Invoke("Add", new object[] {
 87                     x,
 88                     y});
 89         return ((int)(results[0]));
 90     }
 91     
 92     /// <remarks/>
 93     public System.IAsyncResult BeginAdd(int x, int y, System.AsyncCallback callback, object asyncState) {
 94         return this.BeginInvoke("Add", new object[] {
 95                     x,
 96                     y}, callback, asyncState);
 97     }
 98     
 99     /// <remarks/>
100     public int EndAdd(System.IAsyncResult asyncResult) {
101         object[] results = this.EndInvoke(asyncResult);
102         return ((int)(results[0]));
103     }
104     
105     /// <remarks/>
106     public void AddAsync(int x, int y) {
107         this.AddAsync(x, y, null);
108     }
109     
110     /// <remarks/>
111     public void AddAsync(int x, int y, object userState) {
112         if ((this.AddOperationCompleted == null)) {
113             this.AddOperationCompleted = new System.Threading.SendOrPostCallback(this.OnAddOperationCompleted);
114         }
115         this.InvokeAsync("Add", new object[] {
116                     x,
117                     y}, this.AddOperationCompleted, userState);
118     }
119     
120     private void OnAddOperationCompleted(object arg) {
121         if ((this.AddCompleted != null)) {
122             System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
123             this.AddCompleted(this, new AddCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
124         }
125     }
126     
127     /// <remarks/>
128     public new void CancelAsync(object userState) {
129         base.CancelAsync(userState);
130     }
131 }
132 
133 /// <remarks/>
134 [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
135 public delegate void HelloWorldCompletedEventHandler(object sender, HelloWorldCompletedEventArgs e);
136 
137 /// <remarks/>
138 [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
139 [System.Diagnostics.DebuggerStepThroughAttribute()]
140 [System.ComponentModel.DesignerCategoryAttribute("code")]
141 public partial class HelloWorldCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs {
142     
143     private object[] results;
144     
145     internal HelloWorldCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : 
146             base(exception, cancelled, userState) {
147         this.results = results;
148     }
149     
150     /// <remarks/>
151     public string Result {
152         get {
153             this.RaiseExceptionIfNecessary();
154             return ((string)(this.results[0]));
155         }
156     }
157 }
158 
159 /// <remarks/>
160 [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
161 public delegate void AddCompletedEventHandler(object sender, AddCompletedEventArgs e);
162 
163 /// <remarks/>
164 [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
165 [System.Diagnostics.DebuggerStepThroughAttribute()]
166 [System.ComponentModel.DesignerCategoryAttribute("code")]
167 public partial class AddCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs {
168     
169     private object[] results;
170     
171     internal AddCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : 
172             base(exception, cancelled, userState) {
173         this.results = results;
174     }
175     
176     /// <remarks/>
177     public int Result {
178         get {
179             this.RaiseExceptionIfNecessary();
180             return ((int)(this.results[0]));
181         }
182     }
183 }

 

 

一眼是不是就看到了熟悉的代码?,对。

这个url就是服务的地址,更多的信息你可以自己去看里面的代码,分析分析。

 

把这个类拖到你的项目中,测试

 1 protected void Page_Load(object sender, EventArgs e)
 2         {
 3             /*
 4             GetInfo.DataInfoSoapClient client = new GetInfo.DataInfoSoapClient();
 5             int result = client.Add(9, 10);
 6             Response.Write(result);
 7              * */
 8 
 9             DataInfo info = new DataInfo();
10             int result = info.Add(9, 5);
11             Response.Write(result);
12         }

 

如果想生成其他语言呢。比如vb ,从这里可以看出命令:

那就动手尝试下

 

 

还可以生成接口:通过/si命令

你会发现。保存的路径并不是D:\data,因为/si 命令没有这个选项,那怎么办呢?可以切换到D:\data目录

 

很显然。这次是我想要的结果了

 

 

看生成的代码是不是很简洁呢?

 1 //------------------------------------------------------------------------------
 2 // <auto-generated>
 3 //     此代码由工具生成。
 4 //     运行时版本:4.0.30319.18444
 5 //
 6 //     对此文件的更改可能会导致不正确的行为,并且如果
 7 //     重新生成代码,这些更改将会丢失。
 8 // </auto-generated>
 9 //------------------------------------------------------------------------------
10 
11 using System;
12 using System.ComponentModel;
13 using System.Diagnostics;
14 using System.Web.Services;
15 using System.Web.Services.Protocols;
16 using System.Xml.Serialization;
17 
18 // 
19 // 此源代码由 wsdl 自动生成, Version=4.0.30319.1。
20 // 
21 
22 
23 /// <remarks/>
24 [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
25 [System.Web.Services.WebServiceBindingAttribute(Name="DataInfoSoap", Namespace="http://tempuri.org/")]
26 public interface IDataInfoSoap {
27     
28     /// <remarks/>
29     [System.Web.Services.WebMethodAttribute()]
30     [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/HelloWorld", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
31     string HelloWorld();
32     
33     /// <remarks/>
34     [System.Web.Services.WebMethodAttribute()]
35     [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/Add", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
36     int Add(int x, int y);
37 }

 

可以看到接口的名称是 IDataInfoSoap 。那么把这个接口拖到项目中。继承接口试试。