程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# WebService動態調用,

C# WebService動態調用,

編輯:C#入門知識

C# WebService動態調用,


前言

  站在開發者的角度,WebService 技術確實是不再“時髦”。甚至很多人會說,我們不再用它。當然,為了使軟件可以更簡潔,更有層次,更易於實現緩存等機制,我是非常建議將 SOAP 轉為 RESTful 架構風格的。但到目前為止,WebService 在一些Public Institution 中使用還是十分廣泛的。

  這裡主要討論一下關於WebService的調用問題。關於WebService 的調用分為靜態調用和動態調用兩種。

 

靜態調用

  靜態調用的方式是通過“Add Service Reference...”創建客戶端代理類。這種方式讓VS.NET環境來為我們生成服務代理,然後調用對應的Web服務。這樣是使工作簡單了,但是卻將提供Web服務的URL、方法名、參數綁定在一起了,這是VS.NET自動為我們生成Web服務代理的限制。如果發布Web服務的URL改變了,則我們需要重新讓VS.NET生成代理,並重新編譯。很常見的一個場景,某銀行Web服務,因為部署的URL更改,而不得不去重新編譯生成代理,這將會帶來很多不必要的工作量。如果我們使用動態調用就可以避免這種情況。關於靜態調用,不是這篇文章的重點,故不作詳細介紹。

 

動態調用

  在某些情況下我們需要在程序運行期間動態調用一個服務。在 .NET Framework 的 System.Web.Services.Description 命名空間中有我們需要的東西。動態調用有動態調用 WebService、生成客戶端代理程序集文件、生成客戶端代理類源代碼3種方式。

動態調用的具體步驟為:

1)從目標 URL 下載 WSDL 數據;

2)使用 ServiceDescription 創建和格式化 WSDL 文檔文件;

3)使用 ServiceDescriptionImporter 創建客戶端代理類;

4)使用 CodeDom 動態創建客戶端代理類程序集;

5)利用反射調用相關 WebService 方法。

  第一種方式通過在內存中創建動態程序集的方式完成了動態調用過程;第二種方式將客戶端代理類生成程序集文件保存到硬盤,然後可以通過 Assembly.LoadFrom() 載入並進行反射調用。對於需要多次調用的系統,要比每次生成動態程序集效率高出很多;第三種方式是保存源碼文件到硬盤中,然後再進行反射調用。

  這裡將只討論第二種方式,這種方式也是我們在實際應用中最常用的。這種方式只下載 一次 WSDL 信息並創建代理類的程序集。往後程序每次啟動都會反射之前創建好的程序集。如果是 Web服務 URL 變更,只需要修改 App.config 中的 WebServiceUrl 和 ProxyClassName 配置項,並將程序根目錄下生成的程序集刪除即可。下次程序啟動又會重新下載WSDL信息並創建代理類的程序集。 

  App.config文件。 

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3   <appSettings>
 4     <!--WebService地址-->
 5     <add key="WebServiceUrl" value="http://localhost:25060/testService/" />
 6     <!--WebService輸出dll文件名稱-->
 7     <add key="OutputDllFilename" value="TestWebService.dll" />
 8     <!--WebService代理類名稱-->
 9     <add key="ProxyClassName" value="TestService" />
10   </appSettings>
11 </configuration>

  

  創建代理類。 

  1     public class WSHelper
  2     {
  3         /// <summary>
  4         /// 輸出的dll文件名稱
  5         /// </summary>
  6         private static string m_OutputDllFilename;
  7 
  8         /// <summary>
  9         /// WebService代理類名稱
 10         /// </summary>
 11         private static string m_ProxyClassName;
 12 
 13         /// <summary>
 14         /// WebService代理類實例
 15         /// </summary>
 16         private static object m_ObjInvoke;
 17 
 18         /// <summary>
 19         /// 接口方法字典
 20         /// </summary>
 21         private static Dictionary<EMethod, MethodInfo> m_MethodDic = new Dictionary<EMethod, MethodInfo>();
 22 
 23         /// <summary>
 24         /// 創建WebService,生成客戶端代理程序集文件
 25         /// </summary>
 26         /// <param name="error">錯誤信息</param>
 27         /// <returns>返回:true或false</returns>
 28         public static bool CreateWebService(out string error)
 29         {
 30             try
 31             {
 32                 error = string.Empty;
 33                 m_OutputDllFilename = ConfigurationManager.AppSettings["OutputDllFilename"];
 34                 m_ProxyClassName = ConfigurationManager.AppSettings["ProxyClassName"];
 35                 string webServiceUrl = ConfigurationManager.AppSettings["WebServiceUrl"];
 36                 webServiceUrl += "?WSDL";
 37 
 38                 // 如果程序集已存在,直接使用
 39                 if (File.Exists(Path.Combine(Environment.CurrentDirectory, m_OutputDllFilename)))
 40                 {
 41                     BuildMethods();
 42                     return true;
 43                 }
 44 
 45                 //使用 WebClient 下載 WSDL 信息。
 46                 WebClient web = new WebClient();
 47                 Stream stream = web.OpenRead(webServiceUrl);
 48 
 49                 //創建和格式化 WSDL 文檔。
 50                 if (stream != null)
 51                 {
 52                     // 格式化WSDL
 53                     ServiceDescription description = ServiceDescription.Read(stream);
 54 
 55                     // 創建客戶端代理類。
 56                     ServiceDescriptionImporter importer = new ServiceDescriptionImporter
 57                     {
 58                         ProtocolName = "Soap",
 59                         Style = ServiceDescriptionImportStyle.Client,
 60                         CodeGenerationOptions =
 61                             CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync
 62                     };
 63 
 64                     // 添加 WSDL 文檔。
 65                     importer.AddServiceDescription(description, null, null);
 66 
 67                     //使用 CodeDom 編譯客戶端代理類。
 68                     CodeNamespace nmspace = new CodeNamespace();
 69                     CodeCompileUnit unit = new CodeCompileUnit();
 70                     unit.Namespaces.Add(nmspace);
 71 
 72                     ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
 73                     CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
 74 
 75                     CompilerParameters parameter = new CompilerParameters
 76                     {
 77                         GenerateExecutable = false,
 78                         // 指定輸出dll文件名。
 79                         OutputAssembly = m_OutputDllFilename
 80                     };
 81 
 82                     parameter.ReferencedAssemblies.Add("System.dll");
 83                     parameter.ReferencedAssemblies.Add("System.XML.dll");
 84                     parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
 85                     parameter.ReferencedAssemblies.Add("System.Data.dll");
 86 
 87                     // 編譯輸出程序集
 88                     CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
 89 
 90                     // 使用 Reflection 調用 WebService。
 91                     if (!result.Errors.HasErrors)
 92                     {
 93                         BuildMethods();
 94                         return true;
 95                     }
 96                     else
 97                     {
 98                         error = "反射生成dll文件時異常";
 99                     }
100                     stream.Close();
101                     stream.Dispose();
102                 }
103                 else
104                 {
105                     error = "打開WebServiceUrl失敗";
106                 }
107             }
108             catch (Exception ex)
109             {
110                 error = ex.Message;
111             }
112             return false;
113         }
114 
115         /// <summary>
116         /// 反射構建Methods
117         /// </summary>
118         private static void BuildMethods()
119         {
120             Assembly asm = Assembly.LoadFrom(m_OutputDllFilename);
121             //var types = asm.GetTypes();
122             Type asmType = asm.GetType(m_ProxyClassName);
123             m_ObjInvoke = Activator.CreateInstance(asmType);
124 
125             //var methods = asmType.GetMethods();
126             var methods = Enum.GetNames(typeof(EMethod)).ToList();
127             foreach (var item in methods)
128             {
129                 var methodInfo = asmType.GetMethod(item);
130                 if (methodInfo != null)
131                 {
132                     var method = (EMethod)Enum.Parse(typeof(EMethod), item);
133                     m_MethodDic.Add(method, methodInfo);
134                 }
135             }
136         }
137 
138         /// <summary>
139         /// 獲取請求響應
140         /// </summary>
141         /// <param name="method">方法</param>
142         /// <param name="para">參數</param>
143         /// <returns>返回:Json串</returns>
144         public static string GetResponseString(EMethod method, params object[] para)
145         {
146             string result = null;
147             if (m_MethodDic.ContainsKey(method))
148             {
149                 var temp = m_MethodDic[method].Invoke(m_ObjInvoke, para);
150                 if (temp != null)
151                 {
152                     result = temp.ToString();
153                 }
154             }
155             return result;
156         }
157     }

 

  調用接口。

1        // SOAP 請求響應方式
2             TextBox3.Text = WSHelper.GetResponseString(EMethod.Add, Convert.ToInt32(TextBox1.Text), Convert.ToInt32(TextBox2.Text));

 

Http請求 

  除了靜態調用和動態調用,我們還可以發送HttpPost請求來調用WebService的方法。Soap請求就是HTTP POST的一個專用版本,遵循一種特殊的xml消息格式。使用HttpPost請求,對返回結果我們可以手動解析。下面的實現其實和調用WebAPI是完全一樣的。

  1     /// <summary>
  2     /// 請求信息幫助
  3     /// </summary>
  4     public partial class HttpHelper
  5     {
  6         private static HttpHelper m_Helper;
  7         /// <summary>
  8         /// 單例
  9         /// </summary>
 10         public static HttpHelper Helper
 11         {
 12             get { return m_Helper ?? (m_Helper = new HttpHelper()); }
 13         }
 14 
 15         /// <summary>
 16         /// 獲取請求的數據
 17         /// </summary>
 18         /// <param name="strUrl">請求地址</param>
 19         /// <param name="requestMode">請求方式</param>
 20         /// <param name="parameters">參數</param>
 21         /// <param name="requestCoding">請求編碼</param>
 22         /// <param name="responseCoding">響應編碼</param>
 23         /// <param name="timeout">請求超時時間(毫秒)</param>
 24         /// <returns>返回:請求成功響應信息,失敗返回null</returns>
 25         public string GetResponseString(string strUrl, ERequestMode requestMode, Dictionary<string, string> parameters, Encoding requestCoding, Encoding responseCoding, int timeout = 300)
 26         {
 27             string url = VerifyUrl(strUrl);
 28             HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(new Uri(url));
 29 
 30             HttpWebResponse webResponse = null;
 31             switch (requestMode)
 32             {
 33                 case ERequestMode.Get:
 34                     webResponse = GetRequest(webRequest, timeout);
 35                     break;
 36                 case ERequestMode.Post:
 37                     webResponse = PostRequest(webRequest, parameters, timeout, requestCoding);
 38                     break;
 39             }
 40 
 41             if (webResponse != null && webResponse.StatusCode == HttpStatusCode.OK)
 42             {
 43                 using (Stream newStream = webResponse.GetResponseStream())
 44                 {
 45                     if (newStream != null)
 46                         using (StreamReader reader = new StreamReader(newStream, responseCoding))
 47                         {
 48                             string result = reader.ReadToEnd();
 49                             return result;
 50                         }
 51                 }
 52             }
 53             return null;
 54         }
 55 
 56 
 57         /// <summary>
 58         /// get 請求指定地址返回響應數據
 59         /// </summary>
 60         /// <param name="webRequest">請求</param>
 61         /// <param name="timeout">請求超時時間(毫秒)</param>
 62         /// <returns>返回:響應信息</returns>
 63         private HttpWebResponse GetRequest(HttpWebRequest webRequest, int timeout)
 64         {
 65             try
 66             {
 67                 webRequest.Accept = "text/html, application/xhtml+xml, application/json, text/javascript, */*; q=0.01";
 68                 webRequest.Headers.Add("Accept-Language", "zh-cn,en-US,en;q=0.5");
 69                 webRequest.Headers.Add("Cache-Control", "no-cache");
 70                 webRequest.UserAgent = "DefaultUserAgent";
 71                 webRequest.Timeout = timeout;
 72                 webRequest.Method = "GET";
 73 
 74                 // 接收返回信息
 75                 HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
 76                 return webResponse;
 77             }
 78             catch (Exception ex)
 79             {
 80                 return null;
 81             }
 82         }
 83 
 84 
 85         /// <summary>
 86         /// post 請求指定地址返回響應數據
 87         /// </summary>
 88         /// <param name="webRequest">請求</param>
 89         /// <param name="parameters">傳入參數</param>
 90         /// <param name="timeout">請求超時時間(毫秒)</param>
 91         /// <param name="requestCoding">請求編碼</param>
 92         /// <returns>返回:響應信息</returns>
 93         private HttpWebResponse PostRequest(HttpWebRequest webRequest, Dictionary<string, string> parameters, int timeout, Encoding requestCoding)
 94         {
 95             try
 96             {
 97                 // 拼接參數
 98                 string postStr = string.Empty;
 99                 if (parameters != null)
100                 {
101                     parameters.All(o =>
102                     {
103                         if (string.IsNullOrEmpty(postStr))
104                             postStr = string.Format("{0}={1}", o.Key, o.Value);
105                         else
106                             postStr += string.Format("&{0}={1}", o.Key, o.Value);
107 
108                         return true;
109                     });
110                 }
111 
112                 byte[] byteArray = requestCoding.GetBytes(postStr);
113                 webRequest.Accept = "text/html, application/xhtml+xml, application/json, text/javascript, */*; q=0.01";
114                 webRequest.Headers.Add("Accept-Language", "zh-cn,en-US,en;q=0.5");
115                 webRequest.Headers.Add("Cache-Control", "no-cache");
116                 webRequest.UserAgent = "DefaultUserAgent";
117                 webRequest.Timeout = timeout;
118                 webRequest.ContentType = "application/x-www-form-urlencoded";
119                 webRequest.ContentLength = byteArray.Length;
120                 webRequest.Method = "POST";
121 
122                 // 將參數寫入流
123                 using (Stream newStream = webRequest.GetRequestStream())
124                 {
125                     newStream.Write(byteArray, 0, byteArray.Length);
126                     newStream.Close();
127                 }
128 
129                 // 接收返回信息
130                 HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
131                 return webResponse;
132             }
133             catch (Exception ex)
134             {
135                 return null;
136             }
137         }
138 
139 
140         /// <summary>
141         /// 驗證URL
142         /// </summary>
143         /// <param name="url">待驗證 URL</param>
144         /// <returns></returns>
145         private string VerifyUrl(string url)
146         {
147             if (string.IsNullOrEmpty(url))
148                 throw new Exception("URL 地址不可以為空!");
149 
150             if (url.StartsWith("http://", StringComparison.CurrentCultureIgnoreCase))
151                 return url;
152 
153             return string.Format("http://{0}", url);
154         }
155     }

 

  HttpPost 請求響應方式調用接口。

1             // Http Post 請求響應方式
2             string url = m_WebServiceUrl + EMethod.Add.ToString();  //@"http://localhost:25060/testService.asmx/Add";
3             Dictionary<string, string> parameters = new Dictionary<string, string> { { "parameter1", TextBox1.Text }, { "parameter2", TextBox2.Text } };
4             string result = HttpHelper.Helper.GetResponseString(url, ERequestMode.Post, parameters, Encoding.Default, Encoding.UTF8);
5             XElement root = XElement.Parse(result);
6             TextBox3.Text = root.Value;

   

關於SOAP和REST

  我們都知道REST相比SOAP建議的標准更輕量級,甚到用Javascript都可以調用,使用方更方便、高效、簡單。但並不是說REST就是SOAP的替代者。他們都只是實現Web Service(web服務)的兩種不同的架構風格。就安全性等方面來說,SOAP還是更好的。

 

 

 源碼下載

 

 

擴展閱讀

http://www.ruanyifeng.com/blog/2011/09/restful

http://www.cnblogs.com/lema/archive/2012/02/23/2364365.html

http://stevenjohn.iteye.com/blog/1442776

http://blog.linuxphp.org/archives/1505/

http://blog.csdn.net/superjj01/article/details/5270227

http://www.csdn.net/article/2013-06-13/2815744-RESTful-API

http://www.haodaima.net/art/2003909

http://my.oschina.net/lilw/blog/170518

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved