WebService Interface? 什么东西? 为什么要这个玩意儿,它有什么用?
有这样一种情况: 我有一个Client程序,要引用到多个Web Service,这一些Web Service的调用方式是一样的,只是各自Web Service本身的实现有一些区别.那么,对于Client来说,最好的调用方式就是这样的:

IObj?obj?
=
?
new
?WebService1();

obj.Invoke();


obj?
?WebService2();

obj.Invoke();

即通常说到的基于Interface的编程...
但是Web Service的实现和普通的Interface又有一些不同.下面是一个例子,记录了如何使用Web Service Interface.
1. 创建一个接口 ICalculate,加上WebServiceBinding这个Attribute,指明这个Web Service的Name和Namespace:
????[WebServiceBinding(ConformsTo
WsiProfiles.BasicProfile1_1,Name
"
ICalculate
,Namespace
http://dev.robinzhong.com/ICalculate/
)]

????
public
interface
?ICalculate


????
{

????????[WebMethod]

????????int?Add(?a,??b);

????????

????????[WebMethod]

?????????Sub(?b);

????}
2. 创建一个实现了上述接口的类 XCalculate,代码如下:
????[WebService(Namespace?
http://tempuri.org/XCalculate/
)]

????[WebServiceBinding(ConformsTo?
?WsiProfiles.BasicProfile1_1,0)">)]

????[ToolboxItem(
false
class
?XCalculate?:?System.Web.Services.WebService,ICalculate


????
{

????????public??Add(??b?)


????????{

????????????thrownew?NotImplementedException(?);

????????}


?????????Sub(??b?)


????????

????}
这个地方,不用实现的代码.写这两个东西的目的,是为了得到WSDL的定义,注:仅仅只是此SOAP消息的定义,和具体的Service无关.
访问此Web Service地址,得到其WSLD文件 ( http://localhost:2839/XCalculate.asmx?wsdl ).删除 <wsdl :service />节点.
得到下面的WSDL文件:
<
??xml?
version
="1.0"
?encoding
="utf-8"
?
>

wsdl?
:definitions?xmlns:soap
="http://schemas.xmlsoap.org/wsdl/soap/"
?xmlns:tm
="http://microsoft.com/wsdl/mime/textMatching/"
?xmlns:soapenc
="http://schemas.xmlsoap.org/soap/encoding/"
?xmlns:mime
="http://schemas.xmlsoap.org/wsdl/mime/"
?xmlns:tns
="http://dev.robinzhong.com/ICalculate/"
?xmlns:s
="http://www.w3.org/2001/XMLSchema"
?xmlns:soap12
="http://schemas.xmlsoap.org/wsdl/soap12/"
?xmlns:http
="http://schemas.xmlsoap.org/wsdl/http/"
?targetNamespace
?xmlns:wsdl
="http://schemas.xmlsoap.org/wsdl/"

??
</
wsdl
><
:types

????
s?
:schema?elementFormDefault
="qualified"
="http://dev.robinzhong.com/ICalculate/"

??????
s
:element?name
="Add"

????????
:complexType

??????????
:sequence

????????????
:element?minOccurs
="1"
?maxOccurs
?name
="a"
?type
="s:int"
/>
="b"

????????

??????

??????
="AddResponse"
="AddResult"
="Sub"
="SubResponse"
="SubResult"

????????

??????

????

??
:message?name
="AddSoapIn"
:part?name
="parameters"
?element
="tns:Add"
="AddSoapOut"
="tns:AddResponse"
="SubSoapIn"
="tns:Sub"
="SubSoapOut"
="tns:SubResponse"
:portType?name
="ICalculate"
:operation?name
:input?message
="tns:AddSoapIn"
:output?message
="tns:AddSoapOut"
="tns:SubSoapIn"
="tns:SubSoapOut"

??

??
:binding?name
="ICalculate"
="tns:ICalculate"
soap?
:binding?transport
="http://schemas.xmlsoap.org/soap/http"
:operation?soapAction
="http://dev.robinzhong.com/ICalculate/Add"
?style
="document"
:input
:body?use
="literal"
:output

????

????
="http://dev.robinzhong.com/ICalculate/Sub"

????

??

??
="ICalculate1"
soap12?
>
得到了Soap消息的定义和结构,我们就可以用wsdl.exe来生成代码,开始实际的编程工作了.
3. 调用 wsdl.exe /l:cs /n:xxx /out:xxx.cs /si icalculate.wsdl,注意这个/si,完整的参数是 /serverInterface.
生成的代码如下:
????[System.CodeDom.Compiler.GeneratedCodeAttribute(
2.0.50727.42
)]

????[System.Web.Services.WebServiceBindingAttribute(Name
)]


????
?IICalculate?
{

????????


????????/**////?<remarks?/>

????????[System.Web.Services.WebMethodAttribute()]

????????[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://dev.robinzhong.com/ICalculate/Add=http://dev.robinzhong.com/ICalculate/System.Web.Services.Description.SoapBindingUse.Literal,?ParameterStyleSystem.Web.Services.Protocols.SoapParameterStyle.Wrapped)]

?????????b);

????????


????????/**/http://dev.robinzhong.com/ICalculate/Sub?b);

????}
注意: 生成的是一个Interface,不是具体的类.这个Interface,就是我所谓的Web Service Interface (其实实质就是WSDL定义).这个Interface的定义和前面定义的ICalculate,除了多一些Attribute外,其它的一模一样.这些个Attribute就是最大的区别,用来定义WebService调用时接收/发送的Soap消息.
4. 即然Interface都出来了.那么这个时候可以写真正的Web Service了,以下是两个Web Service的示例代码:
http://tempuri.org/
http://localhost/WSInterface/ICalculate.wsdl
?NewCalculate?:?System.Web.Services.WebService?,IICalculate


????
{


????????[WebMethod]

?????????b?)


????????return?a?+?b;

????????}


????????[WebMethod]

?????????b?)


????????-

????}
?
?SimpleCalculate?:?System.Web.Services.WebService,?IICalculate


????
?b?)


?????????b?)


????????

????}
注意WebServiceBinding这个Attribute,在这两个Web Service类中,都使用了这个Attribute,而且设置其Name="ICalculate",Namespace="http://dev.robinzhong.com/ICalculate"... <font color=red>(注:由于IICalculate接口已定义了WebServiceBindingAttribute,所以在其继承的类中也不必定义此Attribute,ASP.NET 2.0测试通过.)</font>
5. Web Service已写好,下面就是Client的调用代码.同样的,也得先生成IICalculate这个接口,同样的方法.
? wsdl.exe /l:cs /n:xxx /out:xxx.cs /si icalculate.wsdl
得到IICalcuate接口.
然后再添加上面两个Web Service中任意一个WebService的引用.比如NewCalculate这个Web Service,得到如下代码:
[System.CodeDom.Compiler.GeneratedCodeAttribute(
System.Web.Services
)]

????[System.Diagnostics.DebuggerStepThroughAttribute()]

????[System.ComponentModel.DesignerCategoryAttribute(
code
)]


????
?partial?
CalculateProxy
:?System.Web.Services.Protocols.SoapHttpClientProtocol?
{

????????

????????private?System.Threading.SendOrPostCallback?AddOperationCompleted;

????????

?????????System.Threading.SendOrPostCallback?SubOperationCompleted;

????????

????????bool?useDefaultCredentialsSetExplicitly;

????????



修改此类,让其从IICalculate继承.然后修改构造函数,让其通过构造函数得到Web Service的Url.如下:
)]


????
:?System.Web.Services.Protocols.SoapHttpClientProtocol,IICalculate?

?useDefaultCredentialsSetExplicitly;

????????


????????/**/<remarks/>


????????
CalculateProxy
(string?url)?
this.Url??url;


????????????if?((.IsLocalFileSystemWebService(.Url)?==true))?
{

????????????????.UseDefaultCredentials?;

????????????????.useDefaultCredentialsSetExplicitly?false;

????????????}


????????????else?

????????}
6. 好了,可以开始测试我们的代码了:
IICalculate?calculate;


calculate?
?CalculateProxy(?
http://localhost:2935/SimpleCalculate.asmx
);

Console.WriteLine(?
calculate.Add(?10,?345?)?=?
+
?calculate.Add(?
10
345
?)?);

Console.WriteLine(?
calculate.Sub(?3455,?234?)?=?
?calculate.Sub(?
3455
234
?)?);


calculate?
http://localhost:2935/NewCalculate.asmx
?)?);
这样就达到了Web Service Interface的目的了--我不管是那里的Web Service,反正只要实现了上面的接口,给我正确的url地址,我就可以调用...
其实,我们可以用更幽雅的方式实现: Contract First . Web Service不是RPC,它只传输数据,你只要定义发送方和接收方的消息格式就够了.
推荐大家看看 :
http://www.thinktecture.com/Resources/Software/WSContractFirst/default.html
http://msdn.microsoft.com/msdnmag/issues/05/05/ServiceStation/
SOA ?

?