webservice主要采用了http协议,http是个基于tcp/ip的应用层协议:(注:现在的大部分webservice开发已经能很好的支持socket的实时通信了.但http依然是它的精髓.)
http采用了请求-----应答模式;
http通信是通过xml串行化通信的......
http通信过程:调用.asmx句柄,xml、xsd、soap和wsdl处理,
xml中主要提供的有三方面:(下面文章引自:http://dev.csdn.net/article/19/19185.shtm)
个人感觉主要要掌握的是soap请求消息和应答消息的xml格式...
消息分派
当.asmx句柄被http管道调用时,通过查看.asmx文件中的webservice声明,确定检查哪个.net类。然后它观察到来的http消息中的信息,确定调用引用类中的哪个方法。为了调用前面例子中的add方法,http请求消息应像下面一样:
上面的http请求消息中有两条信息可以用来确定调用类中的哪个方法:soapaction头或soap体中请求元素的名字。在这个例子中,每种方法都指出了发送者想调用的方法名。
.asmx句柄使用soapaction头的值来实现消息的分派。因此,.asmx句柄查看消息中的soapaction头,使用.net映射检查引用类中的方法。它只考虑标记了[webmethod]属性的方法,但通过查看每种方法的soapaction值再具体确定调用哪个方法。因为我们在类中并没有明确的指定soapaction的值,.asmx句柄认为soapaction的值是web服务的名称空间加上方法名。而且我们也没有指定名称空间,所以句柄就把http://tempuri.org作为默认值。这样add方法的默认soapaction值就是http://tempuri.org/add。
可以按如下方法定制web服务的名称空间。把类标记上[webservice]属性,用[soapdocumentmethod]属性标记webmethods来指定具体的soapaction值。示例如下:
using system.web.services; using system.web.services.protocols; [webservice(namespace="http://example.org/math")] public class mathservice { [webmethod] public double add(double x, double y) { return x + y; } [webmethod] [soapdocumentmethod(action="urn:math:subtract")] public double subtract(double x, double y) { return x - y; } ... }
现在.asmx句柄认为add方法的soapaction值是http://example.org/math/add,subtract方法的soapaction值是urn:math:subtract(因为我们在类中明确定义了)。比如下面的http请求消息调用subtract:
如果.asmx句柄没为http请求消息找到一个soapaction匹配,将会抛出一个异常。如果你不想依赖soapaction头来分派消息,可以引导.asmx句柄使用请求元素名称。采用这种方法需要为类标记上[soapdocumentservice]属性的routingstyle特性,同时也应该指出webmethods不需要soapaction值(在类中设定其值为空)。如下所示:
using system.web.services; using system.web.services.protocols; [webservice(namespace="http://example.org/math")] [soapdocumentservice( routingstyle=soapserviceroutingstyle.requestelement)] public class mathservice { [webmethod] [soapdocumentmethod(action="")] public double add(double x, double y) { return x + y; } [webmethod] [soapdocumentmethod(action="")] public double subtract(double x, double y) { return x - y; } ... }
在这种情况下,句柄甚至不关心soapaction的值,它使用请求元素的名字确定调用方法。比如,在下面的http请求消息中,它希望调用add方法的请求元素的名字是add:
所以当.asmx句柄接收到http消息时它要做的第一件事情就是决定如何分派消息到对应的webmethod。在它真正调用方法之前,还需要将到来的xml映射到.net对象。
将xml映射到对象
一旦webmethod句柄决定了调用哪个方法,它就会将xml消息反串行化为.net对象。随着消息分派,句柄通过reflection检查类,然后决定怎样处理xml消息。xmlserializer类自动完成xml和system.xml.serialization名称空间中类的映射。
xmlserializer能实现任何.net公共类型到xml schema类型的映射,有了这个适当的映射,它能自动的实现.net对象和xml实例文档的映射(见图4)。xmlserializer受xml schema所支持功能的限制,虽不能处理所有复杂的现代对象模型(如非树型的对象图),却能处理开发者常用的复杂类型。
再看前面add的例子,xmlserializer将把x和y元素映射为.net的double值(调用add方法时必须提供的)。add方法返回一个double类型值给调用者,这也需要被串行化为soap应答消息中的一个xml元素。
figure 4. mapping xml to objects
xmlserializer也能自动处理一些复杂类型(除了上面说到的一些限制)。比如,下面的webmethod计算两个点结构之间的距离。
using system; using system.web.services; public class point { public double x; public double y; } [webservice(namespace="urn:geometry")] public class geometry { [webmethod] public double distance(point orig, point dest) { return math.sqrt(math.pow(orig.x-dest.x, 2) + math.pow(orig.y-dest.y, 2)); } }
请求此操作的soap消息将包含一个distance元素,它包含了两个子元素,一个称作orig,另一个是dest,每一个都包括了x和y元素,如下所示:
这种情况下soap应答消息将包含一个distanceresponse元素,它包含一个double 类型的distanceresult子元素。
缺省的xml映射使用方法名作为请求元素名,参数名作为子元素名。每个参数的结构依赖于类型的结构。公共字段和属性的名字简单映射为子元素,如point类中的x和y。应答元素的名字缺省为请求元素的名字后面附加上“response”,应答元素也包含一个子元素,是请求元素名字后面附加“result”。也有可能使用一些固定的映射属性来打破标准的xml映射。比如,你可以使用[xmltype]属性来定制类型的名字和名称空间,使用[xmlelement]和[xmlattribute]属性来控制如何将参数或类成员分别映射为元素或属性,也可以使用[soapdocumentmethod]属性控制怎样把方法本身映射为请求/响应消息中的元素名。比如,检查下面重新定义的distance。
using system; using system.web.services; using system.web.services.protocols; using system.xml.serialization; public class point { [xmlattribute] public double x; [xmlattribute] public double y; } [webservice(namespace="urn:geometry")] public class geometry { [webmethod] [soapdocumentmethod(requestelementname="calcdistance", responseelementname="calculateddistance")] [return: xmlelement("result")] public double distance( [xmlelement("o")]point orig, [xmlelement("d")]point dest) { return math.sqrt(math.pow(orig.x-dest.x, 2) + math.pow(orig.y-dest.y, 2)); } }
它所期望的soap请求消息如下:
.asmx句柄使用soap document/literal风格来实现和描述上面显示的默认映射。意思上说wsdl定义将包含literal xml schema定义,它描述了soap消息中用到的请求和响应元素。
.asmx句柄也能使用soap rpc/encoded风格。这意味着soap体中包含一个rpc调用的xml代表(representation),参数用soap编码规则来串行化。实现这些仅需将[soapdocumentservice] and [soapdocumentmethod]替换为[soaprpcservice] and [soaprpcmethod]属性。
正如你所看到的,我们可能完全定制一个从给定方法到soap消息的映射。xmlserializer提供了一个强大的串行化引擎。
除了处理参数的反串行化,.asmx句柄也能串行化/反串行化soap头。soap头的处理不同于参数,因为它们被认为是典型的无法控制的信息,和具体的方法没有直接的联系。由于这些,头处理主要是通过中间层(interception layers),完全为webmethods屏蔽了头处理。
然而如果想涉足于webmethod中的头信息,你必须提供一个.net类,从soapheader派生而来,它代表了头的xml schema类型。然后定义一个此类型的成员变量作为每一个头实例的占位符。最后标记每个要访问头的webmethod,指定你想要到达的域名。
比如,下面的soap请求包括一个用来进行身份验证的usernametoken头。
更多webservice工作原理。
