惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - hbiftsaa

Live Writer的Code Highlighter插件 在.NET中使用COMAdmin组件管理COM+组件 O/R Mapping再乱弹 blog切换到 http://www.robinzhong.com/ Infopath Cookies(2) - hbiftsaa - 博客园 Infopath Cookies(1) 在Biztalk中使用Log功能:) 定制FxCop规则--检测Release版本中的TestCase 增强SVN的Commit权限控制 电影《幸存者游戏》的管理启示 回来了~..终于回来了... 先和大家告别一段时间了啊:) 转自DRL:向FlashFXP索取上传速度 在SP2中加速P2P类软件 爽啊~进入决赛了:) [建议] [号召] 征求博客园园标 [建议] 提问区的文章加入问题的解决方法/方案 hoho,,,要回家了:) Gmail New Features!
使用Web Service Interface.
hbiftsaa · 2006-08-23 · via 博客园 - hbiftsaa

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

IObj obj = new WebService1();
obj.Invoke();

obj 
= new 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(int a, int b);
        
        [WebMethod]
        
int Sub(int a, int b);
    }

2. 创建一个实现了上述接口的类 XCalculate ,代码如下:

    [WebService(Namespace = "http://tempuri.org/XCalculate/")]
    [WebServiceBinding(ConformsTo 
= WsiProfiles.BasicProfile1_1,Name="ICalculate",Namespace="http://dev.robinzhong.com/ICalculate/")]
    [ToolboxItem(
false)]
    
public class XCalculate : System.Web.Services.WebService,ICalculate
    
{
        
public int Add( int a, int b )
        
{
            
throw new NotImplementedException( );
        }


        
public int Sub( int a, int b )
        
{
            
throw new NotImplementedException( );
        }

    }


这个地方,不用实现的代码.写这两个东西的目的,是为了得到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="http://dev.robinzhong.com/ICalculate/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  
</wsdl><wsdl :types>
    
<:schema elementFormDefault="qualified" targetNamespace="http://dev.robinzhong.com/ICalculate/">
      
</s><:element name="Add">
        
</s><:complexType>
          
</s><:sequence>
            
<:element minOccurs="1" maxOccurs="1" name="a" type="s:int" />
            
<:element minOccurs="1" maxOccurs="1" name="b" type="s:int" />
          
</s>
        
      
      
<:element name="AddResponse">
        
</s><:complexType>
          
</s><:sequence>
            
<:element minOccurs="1" maxOccurs="1" name="AddResult" type="s:int" />
          
</s>
        
      
      
<:element name="Sub">
        
</s><:complexType>
          
</s><:sequence>
            
<:element minOccurs="1" maxOccurs="1" name="a" type="s:int" />
            
<:element minOccurs="1" maxOccurs="1" name="b" type="s:int" />
          
</s>
        
      
      
<:element name="SubResponse">
        
</s><:complexType>
          
</s><:sequence>
            
<:element minOccurs="1" maxOccurs="1" name="SubResult" type="s:int" />
          
</s>
        
      
    
  
</wsdl>
  
<wsdl :message name="AddSoapIn">
    
<wsdl :part name="parameters" element="tns:Add" />
  
</wsdl>
  
<wsdl :message name="AddSoapOut">
    
<wsdl :part name="parameters" element="tns:AddResponse" />
  
</wsdl>
  
<wsdl :message name="SubSoapIn">
    
<wsdl :part name="parameters" element="tns:Sub" />
  
</wsdl>
  
<wsdl :message name="SubSoapOut">
    
<wsdl :part name="parameters" element="tns:SubResponse" />
  
</wsdl>
  
<wsdl :portType name="ICalculate">
    
</wsdl><wsdl :operation name="Add">
      
<wsdl :input message="tns:AddSoapIn" />
      
<wsdl :output message="tns:AddSoapOut" />
    
</wsdl>
    
<wsdl :operation name="Sub">
      
<wsdl :input message="tns:SubSoapIn" />
      
<wsdl :output message="tns:SubSoapOut" />
    
</wsdl>
  
  
<wsdl :binding name="ICalculate" type="tns:ICalculate">
    
<soap :binding transport="http://schemas.xmlsoap.org/soap/http" />
    
</wsdl><wsdl :operation name="Add">
      
<soap :operation soapAction="http://dev.robinzhong.com/ICalculate/Add" style="document" />
      
</wsdl><wsdl :input>
        
<soap :body use="literal" />
      
</wsdl>
      
<wsdl :output>
        
<soap :body use="literal" />
      
</wsdl>
    
    
<wsdl :operation name="Sub">
      
<soap :operation soapAction="http://dev.robinzhong.com/ICalculate/Sub" style="document" />
      
</wsdl><wsdl :input>
        
<soap :body use="literal" />
      
</wsdl>
      
<wsdl :output>
        
<soap :body use="literal" />
      
</wsdl>
    
  
  
<wsdl :binding name="ICalculate1" type="tns:ICalculate">
    
<soap12 :binding transport="http://schemas.xmlsoap.org/soap/http" />
    
</wsdl><wsdl :operation name="Add">
      
<soap12 :operation soapAction="http://dev.robinzhong.com/ICalculate/Add" style="document" />
      
</wsdl><wsdl :input>
        
<soap12 :body use="literal" />
      
</wsdl>
      
<wsdl :output>
        
<soap12 :body use="literal" />
      
</wsdl>
    
    
<wsdl :operation name="Sub">
      
<soap12 :operation soapAction="http://dev.robinzhong.com/ICalculate/Sub" style="document" />
      
</wsdl><wsdl :input>
        
<soap12 :body use="literal" />
      
</wsdl>
      
<wsdl :output>
        
<soap12 :body use="literal" />
      
</wsdl>


得到了Soap消息的定义和结构,我们就可以用wsdl.exe来生成代码,开始实际的编程工作了.

3. 调用 wsdl.exe /l:cs /n:xxx /out:xxx.cs /si icalculate.wsdl ,注意这个/si,完整的参数是 /serverInterface.
生成的代码如下:

    [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl""2.0.50727.42")]
    [System.Web.Services.WebServiceBindingAttribute(Name
="ICalculate", Namespace="http://dev.robinzhong.com/ICalculate/")]
    
public interface IICalculate {
        
        
/// <remarks />
        [System.Web.Services.WebMethodAttribute()]
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute(
"http://dev.robinzhong.com/ICalculate/Add", RequestNamespace="http://dev.robinzhong.com/ICalculate/", ResponseNamespace="http://dev.robinzhong.com/ICalculate/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        
int Add(int a, int b);
        
        
/// <remarks />
        [System.Web.Services.WebMethodAttribute()]
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute(
"http://dev.robinzhong.com/ICalculate/Sub", RequestNamespace="http://dev.robinzhong.com/ICalculate/", ResponseNamespace="http://dev.robinzhong.com/ICalculate/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        
int Sub(int a, int b);
    }

注意: 生成的是一个Interface,不是具体的类.这个Interface,就是我所谓的Web Service Interface (其实实质就是WSDL定义).这个Interface的定义和前面定义的ICalculate,除了多一些Attribute外,其它的一模一样.这些个Attribute就是最大的区别,用来定义WebService调用时接收/发送的Soap消息.

4. 即然Interface都出来了.那么这个时候可以写真正的Web Service了,以下是两个Web Service的示例代码:

    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo 
= WsiProfiles.BasicProfile1_1,Namespace="http://dev.robinzhong.com/ICalculate/",Name="ICalculate",Location="http://localhost/WSInterface/ICalculate.wsdl")]
    [ToolboxItem(
false)]
    
public class NewCalculate : System.Web.Services.WebService ,IICalculate
    
{

        [WebMethod]
        
public int Add( int a, int b )
        
{
            
return a + b;
        }


        [WebMethod]
        
public int Sub( int a, int b )
        
{
            
return a - b;
        }

    }

    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo 
= WsiProfiles.BasicProfile1_1,Name="ICalculate",Namespace="http://dev.robinzhong.com/ICalculate/",Location="http://localhost/WSInterface/ICalculate.wsdl")]
    [ToolboxItem(
false)]
    
public class SimpleCalculate : System.Web.Services.WebService, IICalculate
    
{
        
public int Add( int a, int b )
        
{
            
return a + b;
        }


        
public int Sub( int a, int b )
        
{
            
return a - 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""2.0.50727.42")]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute(
"code")]
    [System.Web.Services.WebServiceBindingAttribute(Name
="ICalculate", Namespace="http://dev.robinzhong.com/ICalculate/")]
    
public partial class CalculateProxy: System.Web.Services.Protocols.SoapHttpClientProtocol {
        
        
private System.Threading.SendOrPostCallback AddOperationCompleted;
        
        
private System.Threading.SendOrPostCallback SubOperationCompleted;
        
        
private bool useDefaultCredentialsSetExplicitly;
        

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

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services""2.0.50727.42")]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute(
"code")]
    [System.Web.Services.WebServiceBindingAttribute(Name
="ICalculate", Namespace="http://dev.robinzhong.com/ICalculate/")]
    
public partial class CalculateProxy: System.Web.Services.Protocols.SoapHttpClientProtocol,IICalculate {
        
        
private System.Threading.SendOrPostCallback AddOperationCompleted;
        
        
private System.Threading.SendOrPostCallback SubOperationCompleted;
        
        
private bool useDefaultCredentialsSetExplicitly;
        
        
/// <remarks/>
        public
CalculateProxy(string url) {
            
this.Url = url;
            
if ((this.IsLocalFileSystemWebService(this.Url) == true)) {
                
this.UseDefaultCredentials = true;
                
this.useDefaultCredentialsSetExplicitly = false;
            }

            
else {
                
this.useDefaultCredentialsSetExplicitly = true;
            }

        }


6. 好了,可以开始测试我们的代码了:

IICalculate calculate;

calculate 
= new CalculateProxy( "http://localhost:2935/SimpleCalculate.asmx");
Console.WriteLine( 
"calculate.Add( 10, 345 ) = " + calculate.Add( 10345 ) );
Console.WriteLine( 
"calculate.Sub( 3455, 234 ) = " + calculate.Sub( 3455234 ) );

calculate 
= new CalculateProxy( "http://localhost:2935/NewCalculate.asmx");
Console.WriteLine( 
"calculate.Add( 10, 345 ) = " + calculate.Add( 10345 ) );
Console.WriteLine( 
"calculate.Sub( 3455, 234 ) = " + calculate.Sub( 3455234 ) );

这样就达到了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 ? :)