什么是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)
/// <summary>
/// 返回两个数的和
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
[WebMethod(Description = "返回两数的和")]
public int Add(int x, int y)
{
return x + y;
}
方法名称上面添加WebMethod特性后。才能暴露在客户端,也就是说可以从远程Web客户端调用该方法
Description是对该方法的描述信息,会显示在客户端。添加完成,保存,F6重新生成代码。刷新浏览器你可以看到代码已经更新
好了。目前为止。服务已经配置好。并且已经发布。供别人免费使用。当有需要计算两个数之和的。就可以调用该服务
现在编写一个测试代码。创建一个项目。右键引用。选择添加服务引用
输入服务地址,命名。单击确定即可。当然你也可以看看该服务提供了那些方法。单击 "发现"
单击确定后。你发现。项目中已经生成了对该服务的引用
现在来编码调用里面的Add方法。创建一个页面。输入以下代码
protected void Page_Load(object sender, EventArgs e)
{
GetInfo.DataInfoSoapClient client = new GetInfo.DataInfoSoapClient();
int result = client.Add(9, 10);
Response.Write(result);
}
运行项目。成功的得到值为:19
那你有没有想过。当添加服务的引用后。内部都做了些什么。为什么添加以后就可以调用了呢?
把光标定位到Add方法。按F12转到方法的定义。
可以看到。其实已经生成了服务端的代码。
那这个代码在哪里呢。你根据项目的层次结构。
到项目的路径中看一看
打开Reference.cs 类。你会发现。里面生成了服务器代码。是自动生成是。别问我怎么知道的。它告诉我的:)
其实引用服务后,就生成服务的客户端代理类
哪天那个发布服务的人。一不小心。把Add方法的 "+" 改成了 "*",
[WebMethod(Description = "返回两数的和")]
public int Add(int x, int y)
{
return x * y;
}
客户端也会相应的更新,这就是一个同步更新
你也会发现。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: 带上位置
从图片的标记可以看出来。已经成功了
来看看生成后的代码:
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.18444
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Serialization;
//
// 此源代码由 wsdl 自动生成, Version=4.0.30319.1。
//
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="DataInfoSoap", Namespace="http://tempuri.org/")]
public partial class DataInfo : System.Web.Services.Protocols.SoapHttpClientProtocol {
private System.Threading.SendOrPostCallback HelloWorldOperationCompleted;
private System.Threading.SendOrPostCallback AddOperationCompleted;
/// <remarks/>
public DataInfo() {
this.Url = "http://localhost:32768/DataInfo.asmx";
}
/// <remarks/>
public event HelloWorldCompletedEventHandler HelloWorldCompleted;
/// <remarks/>
public event AddCompletedEventHandler AddCompleted;
/// <remarks/>
[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)]
public string HelloWorld() {
object[] results = this.Invoke("HelloWorld", new object[0]);
return ((string)(results[0]));
}
/// <remarks/>
public System.IAsyncResult BeginHelloWorld(System.AsyncCallback callback, object asyncState) {
return this.BeginInvoke("HelloWorld", new object[0], callback, asyncState);
}
/// <remarks/>
public string EndHelloWorld(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((string)(results[0]));
}
/// <remarks/>
public void HelloWorldAsync() {
this.HelloWorldAsync(null);
}
/// <remarks/>
public void HelloWorldAsync(object userState) {
if ((this.HelloWorldOperationCompleted == null)) {
this.HelloWorldOperationCompleted = new System.Threading.SendOrPostCallback(this.OnHelloWorldOperationCompleted);
}
this.InvokeAsync("HelloWorld", new object[0], this.HelloWorldOperationCompleted, userState);
}
private void OnHelloWorldOperationCompleted(object arg) {
if ((this.HelloWorldCompleted != null)) {
System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
this.HelloWorldCompleted(this, new HelloWorldCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
}
}
/// <remarks/>
[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)]
public int Add(int x, int y) {
object[] results = this.Invoke("Add", new object[] {
x,
y});
return ((int)(results[0]));
}
/// <remarks/>
public System.IAsyncResult BeginAdd(int x, int y, System.AsyncCallback callback, object asyncState) {
return this.BeginInvoke("Add", new object[] {
x,
y}, callback, asyncState);
}
/// <remarks/>
public int EndAdd(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((int)(results[0]));
}
/// <remarks/>
public void AddAsync(int x, int y) {
this.AddAsync(x, y, null);
}
/// <remarks/>
public void AddAsync(int x, int y, object userState) {
if ((this.AddOperationCompleted == null)) {
this.AddOperationCompleted = new System.Threading.SendOrPostCallback(this.OnAddOperationCompleted);
}
this.InvokeAsync("Add", new object[] {
x,
y}, this.AddOperationCompleted, userState);
}
private void OnAddOperationCompleted(object arg) {
if ((this.AddCompleted != null)) {
System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
this.AddCompleted(this, new AddCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
}
}
/// <remarks/>
public new void CancelAsync(object userState) {
base.CancelAsync(userState);
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
public delegate void HelloWorldCompletedEventHandler(object sender, HelloWorldCompletedEventArgs e);
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
public partial class HelloWorldCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs {
private object[] results;
internal HelloWorldCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
base(exception, cancelled, userState) {
this.results = results;
}
/// <remarks/>
public string Result {
get {
this.RaiseExceptionIfNecessary();
return ((string)(this.results[0]));
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
public delegate void AddCompletedEventHandler(object sender, AddCompletedEventArgs e);
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
public partial class AddCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs {
private object[] results;
internal AddCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
base(exception, cancelled, userState) {
this.results = results;
}
/// <remarks/>
public int Result {
get {
this.RaiseExceptionIfNecessary();
return ((int)(this.results[0]));
}
}
}
一眼是不是就看到了熟悉的代码?,对。
这个url就是服务的地址,更多的你可以自己去看代码,分析分析。
把这个类拖到你的项目中,测试
protected void Page_Load(object sender, EventArgs e)
{
/*
GetInfo.DataInfoSoapClient client = new GetInfo.DataInfoSoapClient();
int result = client.Add(9, 10);
Response.Write(result);
* */
DataInfo info = new DataInfo();
int result = info.Add(9, 5);
Response.Write(result);
}
如果想生成其他语言呢。比如vb ,从这里可以看出命令:
那就动手尝试下
还可以生成接口:通过/si命令
你会发现。保存的路径并不是D:\data,因为/si 命令没有这个选项,那怎么办呢?可以切换到D:\data目录
很显然。这次是我想要的结果了
看生成的代码是不是很简洁呢?
//------------------------------------------------------------------------------// <auto-generated>// 此代码由工具生成。// 运行时版本:4.0.30319.18444//// 对此文件的更改可能会导致不正确的行为,并且如果// 重新生成代码,这些更改将会丢失。// </auto-generated>//------------------------------------------------------------------------------ using System;using System.ComponentModel;using System.Diagnostics;using System.Web.Services;using System.Web.Services.Protocols;using System.Xml.Serialization; // // 此源代码由 wsdl 自动生成, Version=4.0.30319.1。// /// <remarks/>[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")][System.Web.Services.WebServiceBindingAttribute(Name="DataInfoSoap", Namespace="http://tempuri.org/")]public interface IDataInfoSoap { /// <remarks/> [System.Web.Services.WebMethodAttribute()] [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)] string HelloWorld(); /// <remarks/> [System.Web.Services.WebMethodAttribute()] [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)] int Add(int x, int y);}
可以看到接口的名称是 IDataInfoSoap 。那么把这个接口拖到项目中。继承接口试试。