ASP.NET web services 之路
.net 的两个主要特征是创建web service服务器和创建 web services客户端的能力,我们需要了解它的几个组件:用于DISCO(web services Discovery Language,web 服务发现语言)和WSDL(web services Description Language ,web 服务描述语言)
构建服务器
1.确认你是否安装了IIS和.Net Framework (或者安装了vs2005等以上版本)
2.创建一个Asp.net 需要的虚拟目录。将其命名为"Test"(或者使用vs2008创建一个空的web项目).
3.创建一个Test.asmx,把它放在这个虚拟目录中(如果使用vs不需要发布的话,就不需要后者了)。
4.在这个文件的第一行添加webService 指示符(使用vs开发工具就无需下面两步操作)
<%@ webService Class="TestClass" Language="C#"%>
5.引用System和 System.web.Services命名空间。
6.创建一个类"TestClass".
7.使用如下代码:
public int add(int a,int b),给类添加一个方法add.
8.使用webMethod特性把这个方法声明为可调用的XML web Service,如下
[webMethod]
public int add(int a,int b)
{
return a+b;
}
9.我们可以使用本地的地址打开:http://localhost/text/test.asmx .(如果使用的是vs开发工具直接按F5)
web service 公开的方法(都会使用webMethod的特性来标记)
如果你需要查看生成的WSDL文档或者是DISCO的话只需要在地址后面加上"?WSDL"或"?DISCO "就行了
剖析web service
当请求进入IIS时,检查并且是否发出一个.asmx扩展文件,asp.net为了处理程序通过IIS进行注册,因此它请求完全被移交给ASP.Net进程。
ASP.Net工作进程会检查这个请求,并且发现它在machine.config中注册了一个处理程序,用于扩展名为.asmx的资源请求。
接着处理程序创建一个在处理程序中定义的类的实例,并且使用反射查看类所支持的操作以及这些操作如何路由。默认情况下,操作通过SOAPactiion HTTP标头映射
到方法,但这可以改变为映射到SOAPbody的第一个子元素。
一旦消息路由,这个处理程序将使用XML序列化器发序列化XML请求,使之成为方法期望的参数,一旦方法返回返回值和任何输出参数又通过XML序列化映射成XML
。接着一个包含这个XML的SOAP响应被创建,并通过ASP.Net的HttpResquet上下文把响应发送回来,
如果有异常会抛出到SoapException 中,一个SOAP错误将返回,同时HTTP状态码被设置为500或OK.
构建文档字面服务
webService 默认是基于架构的,或者称为字面的XML。
在.NET中,这些文档/字面服务的编程模型的扩展性是相当好的,你可以使用多种XML创建接收或响应的操作。
例如:这个操作将购买订单文档作为SOAP<Body>内的请求(与实际相比,作了大量的简化)
<PurchaseOrder ID="1234">
<Date>1/2/2013</Date>
<Item>Widgets</Item>
<Amout>400</Amout>
</PurchaseOrder>
接收文档响应看起来:
<PurchaseOrderReceipt>
<ReceiptID>5678</ReceipID>
</PurchaseOrderReceipt>
可以用几种方式把这个XML映射成方法。
1.
[webMethod]
[return:XmlElement("PurchaseOrderReceipt")]
public void PurchaseOrder([XmlAttribute]string ID,DateTime Date,int Amout,out string ReceiptID)
{
ReceiptID="5678";
retrun;
}
由于XmlElementAttribute 和XmlAttributeAttribute特性类用于XML序列化,所以必须导入System.Xml.Serialization;
默认情况下,方法名被映射成根元素,方法的每一个参数会被映射成子元素,但是ID参数会映射成XML属性而不是子元素,因为序列化这一点被利用
XmlAttribute特性覆盖。
因为ReceiptID是一个输出参数,它被序列化成XML用于响应,并且它被当成响应包装元素的子元素,默认情况下这个名称是方法的名称结尾添上"Response"
本来应该是"PurchaseOrderResponse",但这里是"PurchaseOrderReceipt"。也是因为有一个特性用于这个方法的返回值;使用XMLAttribute类,这个值就被设置
成正确的值了。
这中序列化的方法被称为Wrapped(包装的),因为方法名称被用于文档的根元素。
2.
[webMethod]
[return:XmlElement("PurchaseOrderReceipt")]
[SoapDocumentMethod(ParameterStyle=SoapParameterStyle.Bare)]
public string PurchaseOrder(string ID,DateTime Date,int Amout)
{
return "5946";
}
这样做的结果是,方法被SOAP请求序列化时,将不会使用方法名称作为包装素(通白的将:就是不会把方法名作为根元素),称为Bare(没有包装的).
通过使用SoapDocumentMethod特性,命名空间要引用:System.web.Services.Protocols
3.
通过第2个列子使用Bare参数风格,使得这些请求和响应都是非描述性的。但是仍然可以创建看起来像包装过的消息。可以创建反映你想创建的XML文档的类,
这些类将会被以一种类似于方法的方式序列化。
首先创建类
public class Po
{
[XmlAttribute]
public string ID;
public DateTime Date;
public int Amount;
}
再创建响应的类
public Class PoReceipt
{
public string ReceiptID=“5649”;
}
[webMethod]
[return:XmlAttribute("PurchaseOrderReceipt")]
[SoapDoucmentMethod(ParameterStyle=SoapParameterSytle.Bare)]
public string PurchaseOrder(Po purchaseOrder)
{
PoReceipt receipt=new PoReceipt();
retrun receipt.ReceiptID;
}
构建文档编程服务
综合上述,所举的例子都是基于文档;通白的讲就是文档在SOAP消息内传递。在webservices 中的这些文档被映射成方法,这纯粹只是一种编程模型思维,这是
请求-响应方式,但不同常规意义的远程方法调用。
还有是基于模式,你可以在WSDL自动生成的类型部分中看到这个模式。模式包含序列化和反序列化XML所以信息时,WSDL将它称为字面(literal)消息。
例如:
要创建这个消息结构,需要在方法声明上改变一样东西,把SoapAttributeMethodAttribute特性的Use属性设置编码的(encoded)
需要引入命名空间 System.web.services.Description
[webMethod]
[return:XmlElement("PurchaseOrderReceipt")]
[SoapDocumentMethod(ParamentStyle=SoapParamentStyle.Bare,Use=SoapBindingUse.Encode)]
public POReceipt PurchaseOrder(PO PurchaseOrder)
{
POReceipt receipt;
return receipt;
}
使用编码的XML特性改成PO类,可以设置XML命名空间为:http://encode/。
[SoapType(Namespace="http://encode/")]
[XmlRoot(Namespace="http://literal/")]
public class PO
{
[XmlAttribute]
public string ID;
public DateTime Date;
public int Amount;
}
注意,ID属性不再是XML属性。编码的SOAP不包括任何特性;全都是元素。
构建RPC编码服务
什么是RPC先了解一下,RPC(Remote Procedure Call Protocol 远程过程调用协议),它是一种通过网络从远程计算机程序请求服务,而不需要了解底层网络技术的协议。
有两种方法可以改变web services,使它从默认处理文档/籽面操作转变到处理RPC编码操作:SoapRpcServiceAttribute特性和SoapRpcMethodAttribute特性。
如果你使用SoapRpcServiceAttribute特性应用在类上,那么所以的方法都是Rpc编码的。但如果你想控制每一个方法,可以在每一个方法上用SoapRpcMethodAttribute特性。
[webMethod]
[SoapRpcMethod]
public POReceipt PurchaseOrder(PO PurchaseOrder)
{
POReceipt receipt;
return receipt;
}
构建单向服务
返回(202 Accepted);但不会有任何其他消息返回、
返回值为Void的方法可以成为单向操作,除此之外,只需要把SoapDocumentMethodAttribute或者SoapRpcMethodAttribute属性的OneWay属性设置为True
例如:
[webMethod]
[SoapRpcMethod(OneWay=true)]
public void SubmitPurchaseOrder(PO PurchaseOrder)
{
retrun;
}
单向服务提供了一种快捷,激发并遗忘(fire-and-forget)的方式来发送消息的简单方法。它们还能更好地提高服务器的性能,因为在你的代码运行时,在保持打开的网咯连接上花费的时间更少。但是如果你要发送一个错误响应到客户端,将无法做到的。
控制路由
如果你有不止一个方法被标记为[webMethod],asp.net 如何来决定哪个方法应该接收和处理这个请求呢?Asp.net有两种选择机制,用于路由或分发:
使用SoapAction HTTP标头
使用<Body>元素的第一个元素
你可以用SoapDocumentServic和SoapRpcService特性来控制路由的方法,默认的情况路由是使用SoapAction的值完成的。这需要服务中每个操作有一个唯一 的SOAPAction,如果做不到你可以是用<Body>元素的第一个元素来代替。
例如:
[SoapDocumentService(RoutingStyle=SoapServiceRoutingStyle.RequestElement)]
public class routing:System.web.Services.webService
{}
还有就是要引入命名空间:System.web.Services.Protocols;
使用SOAP绑定
webService描述语言(WSDL)是一种基于 XML的语法,用于描述XML WebService。 WSDL令人感兴趣的一个特征是它有对操作进行抽象的描述的能力,或者通常说的绑定(binding).
使用webServiceBindingAttribute特性来指明一个webservice实现了一个众所周知的抽象绑定。
这个特性会在自动生成的WSDL文档创建一个WSDL输入语句。然后通过SoapDocumentMethodAttribute或SoapRpcMethodAttribute,或者两者,指明在服务中那些方法实现在绑定中描述的那些操作。
异步实现一个服务器
使用SOAP标头,先不管它有什么用途。
1.创建一个派生于System.Web.Services.Procotols.SoapHeader类的类,它就是你要的序列化成SOAP的类
2.在类中添加前面这个类类型的一个成员变量
3、在任何你想要使用SOAP标头的方法上应用[SoapHeader]特性
4.使用这个成员变量读写数据到标头中
类中要引用System.Web.Services.Procotols和System.Xml.Serialization
public Class AuthHeader:SoapHeader
{
public string UserName;
public string PassWord;
[XmlAttribute]
public String Domain;
}
public Class HeaderTest
{
public AuthHeader auth;
[webMethod]
[SoapHeader("auth")]
public String WhoAmI()
{
retrun auth.UserName;
}
}
[SoapHeader]特性包含许多属性,包括描述标头的指示(Direction)属性,默认值为Out,或者 in或out。
public Class HeaderTest
{
public AuthHeader auth;
[webMethod]
[SoapHeader("auth",Direction=SoapHeaderDirection,InOut)]
public String WhoAmI()
{
retrun auth.UserName;
}
}