• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天下

            記錄修行的印記

            動態調用WebService(C#)

            動態調用WebService(C#)
            轉自:
            http:
            //www.cnblogs.com/xuwb/archive/2012/09/25/2701629.html

            通常我們在程序中需要調用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); 
                     CodeDomProvider provider 
            = new CSharpCodeProvider();//設定編譯參數
                     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 = provider.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)要漂亮的多。


            using System;
            using System.Collections.Generic;
            using System.Text;
            using System.Xml;
            using System.Net;
            using System.Web.Services.Description;
            using System.CodeDom;
            using System.CodeDom.Compiler;
            using System.Reflection;
            namespace WindowsServiceWebDefaultHotCity
            {
                
            /// <summary<
                /// WebService代理類
                
            /// </summary<
                public class WebServiceAgent
                {
                  
            private object agent;
                  
            private Type agentType;
                  
            private const string CODE_NAMESPACE = "Beyondbit.WebServiceAgent.Dynamic";
                  
            /// <summary<
                  /// 構造函數
                  
            /// </summary<
                  /// <param name="url"<</param<
                  public WebServiceAgent(string url)
                  {
                    XmlTextReader reader 
            = new XmlTextReader(url + "?wsdl");

                    
            //創建和格式化 WSDL 文檔
                    ServiceDescription sd = ServiceDescription.Read(reader);

                    
            //創建客戶端代理代理類
                    ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
                    sdi.AddServiceDescription(sd, 
            nullnull);

                    
            //使用 CodeDom 編譯客戶端代理類
                    CodeNamespace cn = new CodeNamespace(CODE_NAMESPACE);
                    CodeCompileUnit ccu 
            = new CodeCompileUnit();
                    ccu.Namespaces.Add(cn);
                    sdi.Import(cn, ccu);
                    Microsoft.CSharp.CSharpCodeProvider icc 
            = new Microsoft.CSharp.CSharpCodeProvider();
                    CompilerParameters cp 
            = new CompilerParameters();
                    CompilerResults cr 
            = icc.CompileAssemblyFromDom(cp, ccu);
                    agentType 
            = cr.CompiledAssembly.GetTypes()[0];
                    agent 
            = Activator.CreateInstance(agentType);
                  }

                  
            ///<summary<
                  ///調用指定的方法
                  
            ///</summary<
                  ///<param name="methodName"<方法名,大小寫敏感</param<
                  ///<param name="args"<參數,按照參數順序賦值</param<
                  ///<returns<Web服務的返回值</returns<
                  public object Invoke(string methodName, params object[] args)
                  {
                    MethodInfo mi 
            = agentType.GetMethod(methodName);
                    
            return this.Invoke(mi, args);
                  }
                  
            ///<summary<
                  ///調用指定方法
                  
            ///</summary<
                  ///<param name="method"<方法信息</param<
                  ///<param name="args"<參數,按照參數順序賦值</param<
                  ///<returns<Web服務的返回值</returns<
                  public object Invoke(MethodInfo method, params object[] args)
                  {
                    
            return method.Invoke(agent, args);
                  }
                  
            public MethodInfo[] Methods
                  {
                    
            get
                    {
                        
            return agentType.GetMethods();
                    }
                  }
                }
            }


            using System;
            using System.Collections.Generic;
            using System.ComponentModel;
            using System.Data;
            using System.Drawing;

            using System.Text;
            using System.Windows.Forms;

            namespace WindowsApplication1
            {
                
            public partial class Form1 : Form
                {
                  
            private string _url = "http://www.baidu.com";
                  
            public Form1()
                  {
                    InitializeComponent();
                    init_Data();
                  }

                  
            public void init_Data()
                  {
                    WindowsServiceWebDefaultHotCity.WebServiceAgent agent 
            = new WindowsServiceWebDefaultHotCity.WebServiceAgent(_url);
                    
            object[] args = new object[6];
                    args[
            0= "PEK";
                    args[
            1= "CAN";
                    args[
            2= "";
                    args[
            3= "2008-08-02";
                    args[
            4= "00:00";
                    args[
            5= "own_9588";
                    
            string text=agent.Invoke("GetAllFlight", args).ToString();
                    textBox1.Text 
            = text;
                  }
                }
            }


            我們都知道,調用WS可以在工程中添加對WS的WEB引用。 
            但是,如果我們不想通過添加引用的方式,而是在代碼中動態引用該怎么辦呢? 
            首先,我們該想到WS的實現也是一個類的形式。 
            其次,WS在傳輸過程中是通過WSDL來進行描述的(使用SOAP協議)。 
            因此,我們需要獲取WS的WSDL描述,并通過該描述來動態生成程序集。 
            最后:通過反射來獲取新生成的程序集,并調用其方法! 
            上述步驟需要引用如下四個名稱空間: 
            using System.Web.Services.Description; //WS的描述 
            //以下幾個用于根據描述動態生成代碼并動態編譯獲取程序集 
            using System.CodeDom; 
            using Microsoft.CSharp; 
            using System.CodeDom.Compiler; 
            上述幾個名稱空間中包括如下幾個重要的類: 
            using System.Web.Services.Description下: 
            ServiceDescription 
            //WS描述 
            ServiceDescriptionImporter //通過描述生成客戶端代理類,特別注意其中的Style 
            以下是MSDN對其的描述: 
            XML Web services 的接口通常由 Web 服務描述語言 (WSDL) 文件來說明。例如,若要獲取有關使用 http:
            //localhost/service.asmx 處公開的 ASP.NET 的 Web 服務的 WSDL 說明,只需導航到 http://localhost/service.asmx?WSDL。使用 ServiceDescriptionImporter 類可以方便地將 WSDL 說明中包含的信息導入到 System.CodeDom.CodeCompileUnit 對象。通過調整 Style 參數的值,可以指示 ServiceDescriptionImporter 實例生成客戶端代理類(通過透明調用該類可提供 Web 服務的功能)或生成抽象類(該類封裝 Web 服務的功能而不實現該功能)。如果將 Style 屬性設置為 Client,則 ServiceDescriptionImporter 生成客戶端代理類,通過調用這些類來提供說明的 Web 服務的功能。如果將 Style 屬性設置為 Server,則 ServiceDescriptionImporter 實例生成抽象類,這些類表示所說明的 XML Web services 的功能而不進行實現。然后,可以通過編寫從這些抽象類繼承的類來對其進行實現,并實現相關的方法。
            using System.CodeDom下: 
            CodedomUnit 
            //它用于設定動態代碼的名稱空間,類名等,可以通過ServiceDescriptionImporter.Import()方法將WS的描述代碼寫入該類,以作動態編譯用

            using System.CodeDom.Compiler下: 
            CodedomProvider 
            //用于創建和檢索代碼生成器和代碼編譯器的實例,我們主要用到其實現子類CShareCodeProvider 
            可以直接用CShareCodeProvider provider=new CShareCodeProvider()來生成,或者用CodedomProvider.CreateProvider("CSharp")來生成 
            ICodeCompiler 
            //用于編譯基于 System.CodeDom 的源代碼表示形式。 
            它通過CodedomProvider的CreateCompiler()方法來 
            CompilerResults 
            //表示從編譯器返回的編譯結果。 它由ICodeCompiler根據指定的編譯器設置從指定的 CodeCompileUnit 所包含的 System.CodeDom 樹中編譯程序集并返回。CompiledAssembly 屬性指示編譯的程序集。

            了解如上信息后,就可動態調用WS了。 
            如下是摘自http:
            //www.cnblogs.com/ruochen/archive/2007/12/11/990427.html的代碼演示:
            Code 

               該方法可以使程序不通過web引用的方式去調用webservices方法,直接在代碼里調用該方法就能達到動態調用webservices的目的。使用前先引用System.Web.Services動態鏈接庫,是.net自帶的dll。

            方法如下:


            using System;
            using System.Collections.Generic;
            using System.Text;
            using System.Net;
            using System.IO;
            using System.Web.Services.Description;
            using System.CodeDom;
            using Microsoft.CSharp;
            using System.CodeDom.Compiler;

            namespace TestSkin
            {
                
            class Webservices
                {
                  
            /// <summary<
                  /// 實例化WebServices
                  
            /// </summary<
                  /// <param name="url"<WebServices地址</param<
                  /// <param name="methodname"<調用的方法</param<
                  /// <param name="args"<把webservices里需要的參數按順序放到這個object[]里</param<
                  public static object InvokeWebService(string url, string methodname, object[] args)
                  {

                    
            //這里的namespace是需引用的webservices的命名空間,在這里是寫死的,大家可以加一個參數從外面傳進來。
                    string @namespace = "client";
                    
            try
                    {
                        
            //獲取WSDL
                        WebClient wc = new WebClient();
                        Stream stream 
            = wc.OpenRead(url + "?WSDL");
                        ServiceDescription sd 
            = ServiceDescription.Read(stream);
                        
            string classname = sd.Services[0].Name;
                        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, truetrue);
                        
            object obj = Activator.CreateInstance(t);
                        System.Reflection.MethodInfo mi 
            = t.GetMethod(methodname);

                        
            return mi.Invoke(obj, args);
                    }
                    
            catch
                    {
                        
            return null;
                    }
                  }
                }
            }

            ===了解上述類和方法后,基本就可以動態調用WS了。 
            特別注意的是:動態編譯后需要用到反射來讀取并執行。因此需要您了解什么是反射及如何反射。  

            web service的動態調用,主要有三種方法。

              
            1、修改config文件。只要你引用了web service,就會在config文件中出現asmx文件的地址。只需要修改該地址即可。

              
            2、程序修改url。web service是集成了System.Web.Service.WebService類的,而該類有一個Url屬性。通過修改該屬性可以達到與方法一一樣的效果,并且比它還要靈活。有的時候,我們需要提供一個列表,有很多的服務器讓用戶選擇。程序根據用戶的選擇連接到不同的服務器上調用web service。這時,就可以用這個方法了。

              
            3、接口引用。有的時候,我們需要調用不同服務器上的web service,但他們彼此又不一樣,只是都實現了同一個接口。這時候,就可以考慮下面的這個方法。只要先引用所有的web service,然后用接口實例來保存創建出來的web service對象即可。

              
            4、動態編譯。這個應該算得上是真正意義上的動態了。有的時候,各個服務器上的web service更新比較快,我們不可能天天去更新代理類的,這個時候就可以用這個方法了。

              在該方法中,有一點限制。就是各個服務器的web service,要么是都繼承了同一個接口,要么是都有一些同樣簽名的方法,而且service的類名最好是一樣的。不過就算不符合這條件也沒關系,后面我會在注釋中注明的。看代碼:


            using System;  
            using System.CodeDom;  
            using System.CodeDom.Compiler;  
            using System.IO;  
            using System.Net;  
            using System.Reflection;  
            using System.Web.Services.Description;  
            using Microsoft.CSharp;  
              
            //獲取Web Service描述  
            WebClient wc= new WebClient();  
            Stream stream 
            = wc.OpenRead("http://localhost/TestService.asmx?WSDL");  //這里指定你自己的web service url,一定要以?WSDL結尾  
            ServiceDescription sd = ServiceDescription.Read(stream);  
            ServiceDescriptionImporter sdi 
            = new ServiceDescriptionImporter();  
            sdi.ProtocolName 
            = "soap";  
            sdi.Style 
            = ServiceDescriptionImportStyle.Client;  
            sdi.AddServiceDescription(sd, 
            nullnull);  
            //指定命名空間  
            CodeNamespace cn = new CodeNamespace("Test");  //這里隨便指定一個命名空間,但要與后面的一致  
            CodeCompileUnit ccu = new CodeCompileUnit();  
            ccu.Namespaces.Add(cn);  
            sdi.Import(cn, ccu);  
            建立C#編譯器  
            CSharpCodeProvider csc 
            = new CSharpCodeProvider();  
            ICodeCompiler icc 
            = csc.CreateCompiler();  
            CompilerParameters cp 
            = new CompilerParameters();  
            cp.GenerateExecutable 
            = false;  
            cp.GenerateInMemory 
            = true;  
            //添加編譯條件  
            cp.ReferencedAssemblies.Add("System.dll");  
            cp.ReferencedAssemblies.Add(
            "System.XML.dll");  
            cp.ReferencedAssemblies.Add(
            "System.Web.Services.dll");  
            //編譯程序集  
            CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);  
            //檢查是否編譯成功  
            if (!cr.Errors.HasErrors)  
            {  
              
            //編譯成功  
              
            //獲取程序集  
              Assembly assembly = cr.CompiledAssembly;  
              
            //獲取程序集類型  
              
            //前面的Test就是命名空間,必須要與前面指定的一致  
              
            //后面的TestService就是service的類名  
              
            //如果所有的服務器都是一致的類名,這里就可以寫死,否則要動態提供類名  
              Type type = assembly.GetType("Test.TestService"true);  
              
            object service = Activator.CreateInstance(type);  
              
            //獲取方法  
              
            //如果所有的服務器都是一致的方法名,這里可以寫死,否則就要動態提供方法名  
              MethodInfo mi = type.GetMethod("HelloWorld");  
              
            //調用方法  
              
            //如果方法沒有參數,第二個參數可以傳遞null,否則就要傳遞object數組,數組元素的順序要與參數的順序一致  
              
            //如果所有服務器的方法簽名都是一致的,object數組的順序就可以寫死了,否則還要動態調整元素的數量及順序  
              mi.Invoke(service, null);  
              
            //最后,返回的是object類型,根據方法的簽名,把返回值轉換成不同的對象即可。  
            }  
            else  
            {  
              
            //這里自己處理編譯錯誤  
            }  

            posted on 2016-06-17 10:53 天下 閱讀(727) 評論(0)  編輯 收藏 引用 所屬分類: C#

            <2012年12月>
            2526272829301
            2345678
            9101112131415
            16171819202122
            23242526272829
            303112345

            導航

            統計

            常用鏈接

            留言簿(4)

            隨筆分類(378)

            隨筆檔案(329)

            鏈接

            最新隨筆

            搜索

            最新評論

            精品蜜臀久久久久99网站| 久久国产精品77777| www久久久天天com| 久久这里有精品| 99久久精品免费看国产| 99蜜桃臀久久久欧美精品网站| 91久久香蕉国产熟女线看| 亚洲va中文字幕无码久久不卡| 久久精品视频91| 久久777国产线看观看精品| 久久精品国产亚洲av麻豆图片 | 国产精品欧美久久久久天天影视| 久久无码AV一区二区三区| 国内精品久久久久久久涩爱 | 亚洲国产精品一区二区三区久久 | 国内精品伊人久久久久av一坑| 亚洲人成无码www久久久| 一级做a爰片久久毛片人呢| 人妻无码αv中文字幕久久| 伊人久久五月天| 欧美一级久久久久久久大| 国产成人精品久久综合| 九九99精品久久久久久| AV色综合久久天堂AV色综合在| 人妻无码中文久久久久专区| 99久久夜色精品国产网站| 2019久久久高清456| 久久久久久午夜精品| 伊人久久五月天| 久久精品国产清自在天天线 | 久久99国产乱子伦精品免费| 亚洲精品白浆高清久久久久久| 久久久久久久波多野结衣高潮| 亚洲欧洲中文日韩久久AV乱码| 女同久久| 九九精品久久久久久噜噜| 欧美激情一区二区久久久| 日韩精品久久无码人妻中文字幕 | 久久成人精品| 久久无码人妻精品一区二区三区 | 久久久精品人妻无码专区不卡 |