首頁 > 軟體

C#中C/S端實現WebService服務

2022-07-22 18:01:03

前言

使用 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>&lt;?xml version="1.0" encoding="UTF-8" ?&gt;&lt;Request&gt;&lt;PK_Type&gt;&lt;Name&gt;LOGIN&lt;/Name&gt;&lt;/PK_Type&gt;&lt;Info&gt;&lt;UserName&gt;cmcc&lt;/UserName&gt;&lt;PassWord&gt;B101341CC2E4D6F5B395C7544B96A826&lt;/PassWord&gt;&lt;FSUID&gt;21202110060001&lt;/FSUID&gt;&lt;FSUIP&gt;192.168.1.253&lt;/FSUIP&gt;&lt;FSUMAC&gt;00:21:92:01:b5:9f&lt;/FSUMAC&gt;&lt;FSUVER&gt;2.0.0.15 for CMCC&lt;/FSUVER&gt;&lt;/Info&gt;&lt;/Request&gt;&#xD;&#xA;

</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服務。

到此這篇關於C#中C/S端實現WebService服務的文章就介紹到這了,更多相關C# C/S端 WebService 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com