C#中C/S端實現(xiàn)WebService服務
前言
使用 C#以B/S方式構建WebService服務十分簡便,即是使用Asp.net在網(wǎng)站中添加WebService服務并使用IIS發(fā)布。但如需要在C/S程序中發(fā)布WebService服務則沒有直接可用的類庫。因此需要使用另外的方式實現(xiàn)WebService服務。
一、實現(xiàn)思路
WebService實際是使用Http并遵循SOAP協(xié)議格式進行交互。能夠進行Http通訊即可實現(xiàn)WebService服務,只是沒了現(xiàn)成的類庫就需要自己編寫解析SOAP格式數(shù)據(jù)包和組織應答包。
二、步驟
1.使用HttpListener構建服務
代碼如下(示例):
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; using System.Net; using System.Web; namespace LadarManufacturabilityTooling { ? ? public class HttpServic ? ? { ? ? ? ? public delegate byte[] OnGetResponseDataHandle(HttpListenerPostValue Sender); ? ? ? ? public event OnGetResponseDataHandle OnGetResponse; ? ? ? ? private static HttpListener httpPostRequest = new HttpListener(); ? ? ? ? private static bool IsRun = true; ? ? ? ? public HttpServic(IPAddress HttpServerIP, int HttpServerPort) ? ? ? ? { ? ? ? ? ? ? httpPostRequest.Prefixes.Add("http://" + HttpServerIP.ToString() + ":" + HttpServerPort.ToString() + "/"); ? ? ? ? ? ? try ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? httpPostRequest.Start(); ? ? ? ? ? ? } ? ? ? ? ? ? catch(Exception ex) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? string Mes = ex.Message; ? ? ? ? ? ? } ? ? ? ? ? ? Thread ThrednHttpPostRequest = new Thread(new ThreadStart(httpPostRequestHandle)); ? ? ? ? ? ? ThrednHttpPostRequest.Start(); ? ? ? ? } ? ? ? ? private void httpPostRequestHandle() ? ? ? ? { ? ? ? ? ? ? while (IsRun) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? try ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? HttpListenerContext requestContext = httpPostRequest.GetContext(); ? ? ? ? ? ? ? ? ? ? Thread threadsub = new Thread(new ParameterizedThreadStart((requestcontext) => ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? HttpListenerContext request = (HttpListenerContext)requestcontext; ? ? ? ? ? ? ? ? ? ? ? ? //獲取Post請求中的參數(shù)和值幫助類 ? ? ? ? ? ? ? ? ? ? ? ? ? HttpListenerPostParaHelper httppost = new HttpListenerPostParaHelper(request); ? ? ? ? ? ? ? ? ? ? ? ? //獲取Post過來的參數(shù)和數(shù)據(jù) ? ? ? ? ? ? ? ? ? ? ? ? ? HttpListenerPostValue lst = httppost.GetHttpListenerPostValue(); ? ? ? ? ? ? ? ? ? ? ? ? byte[] buffer = null; ? ? ? ? ? ? ? ? ? ? ? ? if (lst != null) ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(OnGetResponse != null) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? buffer = OnGetResponse(lst); ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? if(buffer != null) ? ? ? ? ? ? ? ? ? ? ? ? {//Response ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? try ? ? ? ? ? ? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? request.Response.StatusCode = 200; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? request.Response.Headers.Add("SOAPAction", ""); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? request.Response.Headers.Add("User-Agent", "gSOAP/2.8"); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? request.Response.ContentType = "text/xml; charset=utf-8"; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? request.Response.ContentEncoding = Encoding.UTF8; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? request.Response.ContentLength64 = buffer.Length; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? var output = request.Response.OutputStream; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? output.Write(buffer, 0, buffer.Length); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? output.Close(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? catch(Exception ex2) ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? else ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? try ? ? ? ? ? ? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? request.Response.Close(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? catch ? ? ? ? ? ? ? ? ? ? ? ? ? ? { } ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? })); ? ? ? ? ? ? ? ? ? ? threadsub.Start(requestContext); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? catch (Exception ex) ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? string Mes = ex.Message; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? ? ?? ? ? ? ? public void StopHttpThread() ? ? ? ? { ? ? ? ? ? ? IsRun = false; ? ? ? ? ? ? httpPostRequest.Abort(); ? ? ? ? } ? ? } }
啟動服務后在httpPostRequestHandle()函數(shù)中編寫對監(jiān)聽到的服務請求的處理。
//獲取Post過來的參數(shù)和數(shù)據(jù) ? HttpListenerPostValue lst = httppost.GetHttpListenerPostValue();
GetHttpListenerPostValue();函數(shù)作用為取出請求中的數(shù)據(jù)部分和請求的名稱。涉及到的類定義和代碼如下:
/// <summary> ? ? ? /// HttpListenner監(jiān)聽Post請求參數(shù)值實體 ? ? ? /// </summary> ? ? ? public class HttpListenerPostValue ? ? { ? ? ? ? /// <summary> ? ? ? ? ? /// 0=> 參數(shù) ? ? ? ? ? /// 1=> 文件 ? ? ? ? ? /// </summary> ? ? ? ? ? public int type = 0; ? ? ? ? /// <summary> ? ? ? ? /// 請求的類型名稱 ? ? ? ? /// </summary> ? ? ? ? public string name; ? ? ? ? /// <summary> ? ? ? ? /// 數(shù)據(jù)字符串 ? ? ? ? /// </summary> ? ? ? ? public string datas; ? ? }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net; using System.Web; using System.IO; namespace LadarManufacturabilityTooling { ? ? /// <summary> ? ? ? /// 獲取Post請求中的參數(shù)和值幫助類 ? ? ? /// </summary> ? ? ? public class HttpListenerPostParaHelper ? ? { ? ? ? ? private HttpListenerContext request; ? ? ? ? public HttpListenerPostParaHelper(HttpListenerContext request) ? ? ? ? { ? ? ? ? ? ? this.request = request; ? ? ? ? } ? ? ? ? /// <summary> ? ? ? ? ? /// 獲取Post過來的參數(shù)和數(shù)據(jù) ? ? ? ? ? /// </summary> ? ? ? ? ? /// <returns></returns> ? ? ? ? ? public HttpListenerPostValue GetHttpListenerPostValue() ? ? ? ? { ? ? ? ? ? ? try ? ? ? ? ? ? { ? ? ? ? ? ? ? ? HttpListenerPostValue HttpListenerPostValueList = new HttpListenerPostValue(); ? ? ? ? ? ? ? ? if (true) ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? Stream body = request.Request.InputStream; ? ? ? ? ? ? ? ? ? ? Encoding encoding = Encoding.UTF8; ? ? ? ? ? ? ? ? ? ? StreamReader reader = new System.IO.StreamReader(body, encoding); ? ? ? ? ? ? ? ? ? ? if (request.Request.ContentType != null) ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? Console.WriteLine("Client data content type {0}", request.Request.ContentType); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? string datas = reader.ReadToEnd(); ? ? ? ? ? ? ? ? ? ? string Requestname = request.Request.RawUrl.Replace("/",""); ? ? ? ? ? ? ? ? ? ? HttpListenerPostValueList.datas = datas; ? ? ? ? ? ? ? ? ? ? HttpListenerPostValueList.name = Requestname; ? ? ? ? ? ? ? ? ? ? Console.WriteLine(datas); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? return HttpListenerPostValueList; ? ? ? ? ? ? } ? ? ? ? ? ? catch (Exception ex) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? return null; ? ? ? ? ? ? } ? ? ? ? } ? ? } }
以上部分和構建普通的http監(jiān)聽服務并無區(qū)別。
2.處理請求的數(shù)據(jù)
OnGetResponse事件用于處理請求的數(shù)據(jù)并組織回包
代碼如下(示例):
private byte[] ThisHttpServic_OnGetResponse(HttpListenerPostValue Sender) ? ? ? ? { ? ? ? ? ? ? byte[] buffer = null; ? ? ? ? ? ? string restr = ""; ? ? ? ? ? ? //處理收到的請求 ? ? ? ? ? ? switch (Sender.name) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? case "MyServiceName": ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? string xmlOrgstr = ""; ? ? ? ? ? ? ? ? ? ? int iStartPos = Sender.datas.IndexOf("<xmlData>", 1); ? ? ? ? ? ? ? ? ? ? int iStopPos = Sender.datas.IndexOf("</xmlData>", 1); ? ? ? ? ? ? ? ? ? ? if (iStartPos > 0) ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? xmlOrgstr = Sender.datas.Substring(iStartPos + 9, iStopPos - iStartPos - 9); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? string xmlstr = HttpUtility.HtmlDecode(xmlOrgstr); ? ? ? ? ? ? ? ? ? ? string LOGIN_ACK = GetPack(xmlstr); ? ? ? ? ? ? ? ? ? ? restr = GetCompleteSoapString(System.Security.SecurityElement.Escape(LOGIN_ACK)); ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? default: ? ? ? ? ? ? ? ? ? ? restr = ""; ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? } ? ? ? ? ? ? buffer = System.Text.Encoding.UTF8.GetBytes(restr); ? ? ? ? ? ? return buffer; ? ? ? ? }
需要從收到的http請求的數(shù)據(jù)部分提取出WebService服務的參數(shù)。
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:client1="http://LSCService.chinamobile.com" xmlns:service1="http://FSUService.chinamobile.com"> <SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <client1:invoke> <xmlData><?xml version="1.0" encoding="UTF-8" ?><Request><PK_Type><Name>LOGIN</Name></PK_Type><Info><UserName>cmcc</UserName><PassWord>B101341CC2E4D6F5B395C7544B96A826</PassWord><FSUID>21202110060001</FSUID><FSUIP>192.168.1.253</FSUIP><FSUMAC>00:21:92:01:b5:9f</FSUMAC><FSUVER>2.0.0.15 for CMCC</FSUVER></Info></Request>
 </xmlData> </client1:invoke>< /SOAP-ENV:Body> </SOAP-ENV:Envelope>
收到的數(shù)據(jù)包原文(Sender.datas)為:
作為示例的服務的參數(shù)名為xmlData從SOAP中截取出參數(shù)的字符串進行處理。
由于xmlData中的內(nèi)容是一串xml字符,SOAP傳輸時經(jīng)過了轉義,因此還需要轉義回來。
string xmlstr = HttpUtility.HtmlDecode(xmlOrgstr);
處理完相應的業(yè)務,將需要回復的數(shù)據(jù)加上SOAP協(xié)議的頭尾組好回復包返回。需要轉義的部分記得進行符號轉義。
System.Security.SecurityElement.Escape(LOGIN_ACK)
SOAP協(xié)議的頭尾根據(jù)WebService服務函數(shù)的定義有所不同,需要自行組織。示例如下:
/// <summary> /// 返回完整的SOAP包 /// </summary> /// <param name="XmlData">應答部分</param> /// <returns></returns> public static string GetCompleteSoapString(string XmlData) { string restr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"" + " xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"" + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" + " xmlns:client1=\"http://LService.mobile.com\"" + " xmlns:service1=\"http://FService.mobile.com\">" + "<SOAP-ENV:Body>" + "<client1:invokeResponse><invokeReturn>"; string restrEnd = "</invokeReturn></client1:invokeResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>"; restr = restr + XmlData + restrEnd; return restr; }
總結
既然C# 并未提供在C/S程序使用的WebService服務的.Net庫,那么就使用HttpListener監(jiān)聽http請求自行解出其中的輸入數(shù)據(jù),再根據(jù)SOAP協(xié)議進行處理。以此方式實現(xiàn)WebService服務。
到此這篇關于C#中C/S端實現(xiàn)WebService服務的文章就介紹到這了,更多相關C# C/S端 WebService 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
淺析C#?AsyncLocal如何在異步間進行數(shù)據(jù)流轉
在異步編程中,處理異步操作之間的數(shù)據(jù)流轉是一個比較常用的操作,C#異步編程提供了一個強大的工具來解決這個問題,那就是AsyncLocal,下面我們就來看看AsyncLocal的原理和用法吧2023-08-08WPF利用TabControl控件實現(xiàn)拖拽排序功能
在UI交互中,拖拽操作是一種非常簡單友好的交互,這篇文章主要為大家介紹了WPF如何利用TabControl控件實現(xiàn)拖拽排序功能,需要的小伙伴可以參考一下2023-10-10C#調(diào)用AForge實現(xiàn)攝像頭錄像的示例代碼
這篇文章主要介紹了C#調(diào)用AForge實現(xiàn)攝像頭錄像的示例代碼,非常具有實用價值,需要的朋友可以參考下2017-09-09C# 中的IComparable和IComparer的使用及區(qū)別
這篇文章主要介紹了C# 中的IComparable和IComparer的使用及區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-01-01