[ZT].Net中動態建立和調用WebServices的方法

 
   通常我們在程序中需要調用WebService時,都是通過「添加Web引用」,讓VS.NET環境來為我們生成服務代理,然後調用對應的Web服務。這樣是使工作簡單了,但是卻和提供Web服務的URL、方法名、參數綁定在一起了,這是VS.NET自動為我們生成Web服務代理的限制。如果哪一天發佈Web服務的URL改變了,則我們需要重新讓VS.NET生成代理,並重新編譯。在某些情況下,這可能是不能忍受的,我們需要動態調用WebService的能力。比如我們可以把Web服務的URL保存在配置文件中,這樣,當服務URL改變時,只需要修改配置文件就可以了。
     說了這麼多,實際上我們要實現這樣的功能:
public static object InvokeWebService(string url,  string methodname, object[] args)
     其中,url是Web服務的地址,methodname是要調用服務方法名,args是要調用Web服務所需的參數,返回值就是web服務返回的結果了。

     要實現這樣的功能,你需要這幾個方面的技能:反射、CodeDom、編程使用C#編譯器、WebService。在瞭解這些知識後,就可以容易的實現web服務的動態調用了:
         #region InvokeWebService
        
//動態調用web服務
        public static object InvokeWebService(string url, string methodname, object[] args)
         {
            
return WebServiceHelper.InvokeWebService(url ,null ,methodname ,args) ;
         }

        
public static object InvokeWebService(string url,  string classname, string methodname, object[] args)
         {
            
string @namespace = "EnterpriseServerBase.WebService.DynamicWebCalling" ;
            
if((classname == null) ||(classname == ""))
             {
                 classname
= WebServiceHelper.GetWsClassName(url) ;
             }

            
try
             {
                
//獲取WSDL
                 WebClient wc                   = new WebClient();
                 Stream stream                  
= wc.OpenRead(url+"?WSDL");
                 ServiceDescription sd          
= ServiceDescription.Read(stream);
                 ServiceDescriptionImporter sdi
= new ServiceDescriptionImporter();
                 sdi.AddServiceDescription(sd,
"","");
                 CodeNamespace cn                
= new CodeNamespace(@namespace);
                
                
//生成客戶端代理類代碼
                 CodeCompileUnit ccu             = new CodeCompileUnit();
                 ccu.Namespaces.Add(cn);
                 sdi.Import(cn ,ccu);
                 CSharpCodeProvider csc          
= new CSharpCodeProvider();
                 ICodeCompiler icc               
= csc.CreateCompiler();
                
                
//設定編譯參數
                 CompilerParameters cplist       = new CompilerParameters();
                 cplist.GenerateExecutable       
= false;
                 cplist.GenerateInMemory         
= true;
                 cplist.ReferencedAssemblies.Add(
"System.dll");
                 cplist.ReferencedAssemblies.Add(
"System.XML.dll");
                 cplist.ReferencedAssemblies.Add(
"System.Web.Services.dll");
                 cplist.ReferencedAssemblies.Add(
"System.Data.dll");

                
//編譯代理類
                 CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu);
                
if(true == cr.Errors.HasErrors)
                 {
                     System.Text.StringBuilder sb
= new System.Text.StringBuilder();
                    
foreach(System.CodeDom.Compiler.CompilerError ce in cr.Errors)
                     {
                         sb.Append(ce.ToString());
                         sb.Append(System.Environment.NewLine);
                     }
                    
throw new Exception(sb.ToString());
                 }

                
//生成代理實例,並調用方法
                 System.Reflection.Assembly assembly = cr.CompiledAssembly;
                 Type t
= assembly.GetType(@namespace+"."+classname,true,true);
                
object obj = Activator.CreateInstance(t);
                 System.Reflection.MethodInfo mi
= t.GetMethod(methodname);

                
return mi.Invoke(obj,args);
             }
            
catch(Exception ex)
             {
                
throw new Exception(ex.InnerException.Message,new Exception(ex.InnerException.StackTrace));
             }
         }

        
private static string GetWsClassName(string wsUrl)
         {
            
string[] parts = wsUrl.Split('/') ;
            
string[] pps   = parts[parts.Length-1].Split('.') ;

            
return pps[0] ;
         }
        
#endregion

     上面的註釋已經很好的說明了各代碼段的功能,下面給個例子看看,這個例子是通過訪問http://www.webservicex.net/globalweather.asmx 服務來獲取各大城市的天氣狀況。
             string url = "http://www.webservicex.net/globalweather.asmx" ;
            
string[] args = new string[2] ;
             args[
0] = this.textBox_CityName.Text ;
             args[
1] = "China" ;
            
object result = WebServiceHelper.InvokeWebService(url ,"GetWeather" ,args) ;
            
this.label_Result.Text = result.ToString() ;

     上述的例子中,調用web服務使用了兩個參數,第一個是城市的名字,第二個是國家的名字,Web服務返回的是XML文檔,可以從其中解析出溫度、風力等天氣情況。
    
     最後說一下,C#雖然仍屬於靜態語言之列,但是其動態能力也是很強大的,不信,你可以看看Spring.net的AOP實現,這種「無侵入」的AOP實現比通常的.NET聲明式AOP實現(一般是通過AOP Attribute)要漂亮的多。

完整類的代碼:
  1 //-----代码开始
  2 
  3 using System;
  4 
  5 using System.IO;
  6 
  7 using System.Configuration;
  8 
  9 using System.CodeDom;
 10 
 11 using System.CodeDom.Compiler;
 12 
 13 using System.Net;
 14 
 15 using System.Web.Services;
 16 
 17 using System.Web.Services.Description;
 18 
 19 using Microsoft.CSharp;
 20 
 21 using System.Collections;
 22 
 23 using System.Reflection;
 24 
 25  
 26 
 27 namespace WHelper 
 28 
 29 {
 30 
 31      /// <summary>
 32 
 33      /// WebServiceHelper 的摘要说明。
 34 
 35      /// </summary>
 36 
 37      public class WebServiceHelper
 38 
 39      {
 40 
 41          private string @namespace = "EnterpriseServerBase.WebService.DynamicWebCalling" ;        //命名空间
 42 
 43          private Assembly assembly = null;    //程序集;
 44 
 45          private string classname = string.Empty;  //类名称;
 46 
 47          private Type t;             //表示类型;
 48 
 49          private object obj = null;       //表示实例;
 50 
 51          private Boolean isSuccess = false;   //是否创建实例成功;
 52 
 53  
 54 
 55  
 56 
 57          public WebServiceHelper(string Url,string classname)
 58 
 59          {
 60 
 61               if(classname == null || classname == string.Empty)
 62 
 63                    this.classname = GetWsClassName(Url);
 64 
 65               else
 66 
 67                    this.classname = classname;
 68 
 69  
 70 
 71               try
 72 
 73               {
 74 
 75                    //获取WSDL
 76 
 77                    WebClient wc                   = new WebClient();
 78 
 79                    Stream stream                  = wc.OpenRead(Url+"?WSDL");
 80 
 81                    ServiceDescription sd          = ServiceDescription.Read(stream);
 82 
 83                    ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
 84 
 85                    sdi.AddServiceDescription(sd,"","");
 86 
 87                    CodeNamespace cn                = new CodeNamespace(@namespace);
 88 
 89                    stream.Close();
 90 
 91  
 92 
 93                    //生成客户端代理类代码
 94 
 95                    CodeCompileUnit ccu             = new CodeCompileUnit();
 96 
 97                    ccu.Namespaces.Add(cn);
 98 
 99                    sdi.Import(cn ,ccu); 
100 
101                    CSharpCodeProvider csc          = new CSharpCodeProvider();
102 
103                    ICodeCompiler icc               = csc.CreateCompiler();
104 
105                 
106 
107                    //设定编译参数
108 
109                    CompilerParameters cplist       = new CompilerParameters();
110 
111                    cplist.GenerateExecutable       = false;
112 
113                    cplist.GenerateInMemory         = true;
114 
115                    cplist.ReferencedAssemblies.Add("System.dll");
116 
117                    cplist.ReferencedAssemblies.Add("System.XML.dll");
118 
119                    cplist.ReferencedAssemblies.Add("System.Web.Services.dll");
120 
121                    cplist.ReferencedAssemblies.Add("System.Data.dll");
122 
123  
124 
125                    //编译代理类
126 
127                    CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu);
128 
129                    
130 
131                    if(true == cr.Errors.HasErrors)
132 
133                    {
134 
135                        System.Text.StringBuilder sb = new System.Text.StringBuilder();
136 
137                        foreach(System.CodeDom.Compiler.CompilerError ce in cr.Errors)
138 
139                        {
140 
141                             sb.Append(ce.ToString());
142 
143                             sb.Append(System.Environment.NewLine);
144 
145                        }
146 
147                        throw new Exception(sb.ToString());
148 
149                    }                          
150 
151    
152 
153                    assembly = cr.CompiledAssembly;
154 
155               }
156 
157               catch (System.Exception ex)
158 
159               {
160 
161                    throw new Exception(ex.InnerException.Message,new Exception(ex.InnerException.StackTrace));
162 
163               }
164 
165          }
166 
167  
168 
169          private Boolean CreateInstance()
170 
171          {
172 
173               try
174 
175               {
176 
177                    t = assembly.GetType(@namespace+"."+classname,true,true);
178 
179                    obj = Activator.CreateInstance(t);
180 
181                    isSuccess = true;
182 
183               }
184 
185               catch (System.Exception e)
186 
187               {
188 
189                    throw new Exception(e.Message);
190 
191               }
192 
193               return isSuccess;
194 
195          }
196 
197  
198 
199          public object InvokeWebService(string methodanme,object[] parms)
200 
201          {
202 
203  
204 
205               if(!isSuccess)
206 
207               {
208 
209                    CreateInstance();
210 
211               }
212 
213  
214 
215               try
216 
217               {             
218 
219                    System.Reflection.MethodInfo mi = t.GetMethod(methodanme);
220 
221  
222 
223                    return mi.Invoke(obj,parms);
224 
225             
226 
227               }
228 
229               catch (System.Exception ex)
230 
231               {
232 
233                    throw new Exception(ex.InnerException.Message,new Exception(ex.InnerException.StackTrace));
234 
235               }
236 
237  
238 
239          }
240 
241  
242 
243          private string GetWsClassName(string wsUrl)
244 
245          {
246 
247               string[] parts = wsUrl.Split('/') ;
248 
249               string[] pps   = parts[parts.Length-1].Split('.') ;
250 
251  
252 
253               return pps[0] ;
254 
255          }
256 
257      }
258 
259 }
260 
261  
262 
263 //---代码结束
264 
posted on 2008-09-25 09:12  巍巍边疆  阅读(1161)  评论(1编辑  收藏  举报