• <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>

            天下

            記錄修行的印記

            動態(tài)調(diào)用WebService(C#)

            動態(tài)調(diào)用WebService(C#)
            轉(zhuǎn)自:
            http:
            //www.cnblogs.com/xuwb/archive/2012/09/25/2701629.html

            通常我們在程序中需要調(diào)用WebService時,都是通過“添加Web引用”,讓VS.NET環(huán)境來為我們生成服務(wù)代理,然后調(diào)用對應(yīng)的Web服務(wù)。這樣是使工作簡單了,但是卻和提供Web服務(wù)的URL、方法名、參數(shù)綁定在一起了,這是VS.NET自動為我們生成Web服務(wù)代理的限制。如果哪一天發(fā)布Web服務(wù)的URL改變了,則我們需要重新讓VS.NET生成代理,并重新編譯。在某些情況下,這可能是不能忍受的,我們需要動態(tài)調(diào)用WebService的能力。比如我們可以把Web服務(wù)的URL保存在配置文件中,這樣,當(dāng)服務(wù)URL改變時,只需要修改配置文件就可以了。
                說了這么多,實(shí)際上我們要實(shí)現(xiàn)這樣的功能:

            public static object InvokeWebService(string url,  string methodname, object[] args)  
                其中,url是Web服務(wù)的地址,methodname是要調(diào)用服務(wù)方法名,args是要調(diào)用Web服務(wù)所需的參數(shù),返回值就是web服務(wù)返回的結(jié)果了。 要實(shí)現(xiàn)這樣的功能,你需要這幾個方面的技能:反射、CodeDom、編程使用C#編譯器、WebService。在了解這些知識后,就可以容易的實(shí)現(xiàn)web服務(wù)的動態(tài)調(diào)用了:


                
            #region InvokeWebService
                
            //動態(tài)調(diào)用web服務(wù)
                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();//設(shè)定編譯參數(shù)
                     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());
                     }

                    
            //生成代理實(shí)例,并調(diào)用方法
                     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

            上面的注釋已經(jīng)很好的說明了各代碼段的功能,下面給個例子看看,這個例子是通過訪問http:
            //www.webservicex.net/globalweather.asmx 服務(wù)來獲取各大城市的天氣狀況。

                 
            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() ;
            上述的例子中,調(diào)用web服務(wù)使用了兩個參數(shù),第一個是城市的名字,第二個是國家的名字,Web服務(wù)返回的是XML文檔,可以從其中解析出溫度、風(fēng)力等天氣情況。
                
                 最后說一下,C#雖然仍屬于靜態(tài)語言之列,但是其動態(tài)能力也是很強(qiáng)大的,不信,你可以看看Spring.net的AOP實(shí)現(xiàn),這種“無侵入”的AOP實(shí)現(xiàn)比通常的.NET聲明式AOP實(shí)現(xiàn)(一般是通過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<
                  /// 構(gòu)造函數(shù)
                  
            /// </summary<
                  /// <param name="url"<</param<
                  public WebServiceAgent(string url)
                  {
                    XmlTextReader reader 
            = new XmlTextReader(url + "?wsdl");

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

                    
            //創(chuàng)建客戶端代理代理類
                    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<
                  ///調(diào)用指定的方法
                  
            ///</summary<
                  ///<param name="methodName"<方法名,大小寫敏感</param<
                  ///<param name="args"<參數(shù),按照參數(shù)順序賦值</param<
                  ///<returns<Web服務(wù)的返回值</returns<
                  public object Invoke(string methodName, params object[] args)
                  {
                    MethodInfo mi 
            = agentType.GetMethod(methodName);
                    
            return this.Invoke(mi, args);
                  }
                  
            ///<summary<
                  ///調(diào)用指定方法
                  
            ///</summary<
                  ///<param name="method"<方法信息</param<
                  ///<param name="args"<參數(shù),按照參數(shù)順序賦值</param<
                  ///<returns<Web服務(wù)的返回值</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;
                  }
                }
            }


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

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

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

               該方法可以使程序不通過web引用的方式去調(diào)用webservices方法,直接在代碼里調(diào)用該方法就能達(dá)到動態(tài)調(diào)用webservices的目的。使用前先引用System.Web.Services動態(tài)鏈接庫,是.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<
                  /// 實(shí)例化WebServices
                  
            /// </summary<
                  /// <param name="url"<WebServices地址</param<
                  /// <param name="methodname"<調(diào)用的方法</param<
                  /// <param name="args"<把webservices里需要的參數(shù)按順序放到這個object[]里</param<
                  public static object InvokeWebService(string url, string methodname, object[] args)
                  {

                    
            //這里的namespace是需引用的webservices的命名空間,在這里是寫死的,大家可以加一個參數(shù)從外面?zhèn)鬟M(jìn)來。
                    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();

                        
            //設(shè)定編譯參數(shù)
                        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());
                        }

                        
            //生成代理實(shí)例,并調(diào)用方法
                        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;
                    }
                  }
                }
            }

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

            web service的動態(tài)調(diào)用,主要有三種方法。

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

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

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

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

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


            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結(jié)尾  
            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的類名  
              
            //如果所有的服務(wù)器都是一致的類名,這里就可以寫死,否則要動態(tài)提供類名  
              Type type = assembly.GetType("Test.TestService"true);  
              
            object service = Activator.CreateInstance(type);  
              
            //獲取方法  
              
            //如果所有的服務(wù)器都是一致的方法名,這里可以寫死,否則就要動態(tài)提供方法名  
              MethodInfo mi = type.GetMethod("HelloWorld");  
              
            //調(diào)用方法  
              
            //如果方法沒有參數(shù),第二個參數(shù)可以傳遞null,否則就要傳遞object數(shù)組,數(shù)組元素的順序要與參數(shù)的順序一致  
              
            //如果所有服務(wù)器的方法簽名都是一致的,object數(shù)組的順序就可以寫死了,否則還要動態(tài)調(diào)整元素的數(shù)量及順序  
              mi.Invoke(service, null);  
              
            //最后,返回的是object類型,根據(jù)方法的簽名,把返回值轉(zhuǎn)換成不同的對象即可。  
            }  
            else  
            {  
              
            //這里自己處理編譯錯誤  
            }  

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

            <2015年12月>
            293012345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            導(dǎo)航

            統(tǒng)計

            常用鏈接

            留言簿(4)

            隨筆分類(378)

            隨筆檔案(329)

            鏈接

            最新隨筆

            搜索

            最新評論

            污污内射久久一区二区欧美日韩| 中文字幕人妻色偷偷久久| 久久亚洲精品成人av无码网站| 久久婷婷五月综合色奶水99啪| 亚洲精品成人久久久| 麻豆精品久久久久久久99蜜桃| 亚洲日本va中文字幕久久| 国产精品99久久久久久人| 精品久久久无码中文字幕天天| 欧美一区二区久久精品| 久久久久亚洲AV片无码下载蜜桃| 日本免费一区二区久久人人澡 | 热久久最新网站获取| 丁香五月网久久综合| 热久久国产欧美一区二区精品| 蜜臀久久99精品久久久久久小说| 伊人色综合久久天天| 亚洲AV日韩精品久久久久| 久久久久亚洲AV成人网人人网站| 欧美大香线蕉线伊人久久| 久久国产AVJUST麻豆| 97久久精品人人澡人人爽| 亚洲精品无码成人片久久| 久久一区二区三区99| 曰曰摸天天摸人人看久久久| 久久久久亚洲AV无码网站| 久久99九九国产免费看小说| 久久不见久久见免费影院www日本| 久久久久久久亚洲Av无码| 色婷婷综合久久久久中文一区二区 | 99久久国产亚洲高清观看2024| 久久久久久久久久久久中文字幕 | 久久午夜电影网| 久久99精品国产99久久| 99久久精品毛片免费播放| 国产午夜福利精品久久2021 | 国产精品99久久久精品无码| 无码乱码观看精品久久| 午夜精品久久久久9999高清| 亚洲一区精品伊人久久伊人| 日本精品一区二区久久久|