C# C/S端 WebService
Menglon 人气:0前言
使用 C#以B/S方式构建WebService服务十分简便,即是使用Asp.net在网站中添加WebService服务并使用IIS发布。但如需要在C/S程序中发布WebService服务则没有直接可用的类库。因此需要使用另外的方式实现WebService服务。
一、实现思路
WebService实际是使用Http并遵循SOAP协议格式进行交互。能够进行Http通讯即可实现WebService服务,只是没了现成的类库就需要自己编写解析SOAP格式数据包和组织应答包。
二、步骤
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请求中的参数和值帮助类 HttpListenerPostParaHelper httppost = new HttpListenerPostParaHelper(request); //获取Post过来的参数和数据 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()函数中编写对监听到的服务请求的处理。
//获取Post过来的参数和数据 HttpListenerPostValue lst = httppost.GetHttpListenerPostValue();
GetHttpListenerPostValue();函数作用为取出请求中的数据部分和请求的名称。涉及到的类定义和代码如下:
/// <summary> /// HttpListenner监听Post请求参数值实体 /// </summary> public class HttpListenerPostValue { /// <summary> /// 0=> 参数 /// 1=> 文件 /// </summary> public int type = 0; /// <summary> /// 请求的类型名称 /// </summary> public string name; /// <summary> /// 数据字符串 /// </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请求中的参数和值帮助类 /// </summary> public class HttpListenerPostParaHelper { private HttpListenerContext request; public HttpListenerPostParaHelper(HttpListenerContext request) { this.request = request; } /// <summary> /// 获取Post过来的参数和数据 /// </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监听服务并无区别。
2.处理请求的数据
OnGetResponse事件用于处理请求的数据并组织回包
代码如下(示例):
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请求的数据部分提取出WebService服务的参数。
<?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>
收到的数据包原文(Sender.datas)为:
作为示例的服务的参数名为xmlData从SOAP中截取出参数的字符串进行处理。
由于xmlData中的内容是一串xml字符,SOAP传输时经过了转义,因此还需要转义回来。
string xmlstr = HttpUtility.HtmlDecode(xmlOrgstr);
处理完相应的业务,将需要回复的数据加上SOAP协议的头尾组好回复包返回。需要转义的部分记得进行符号转义。
System.Security.SecurityElement.Escape(LOGIN_ACK)
SOAP协议的头尾根据WebService服务函数的定义有所不同,需要自行组织。示例如下:
/// <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监听http请求自行解出其中的输入数据,再根据SOAP协议进行处理。以此方式实现WebService服务。
加载全部内容