C#中C/S端实现WebService服务

作者:Menglon 时间:2023-10-16 06:01:43 

前言

使用 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;
       }

来源:https://blog.csdn.net/qq_35034209/article/details/125744586

标签:C#,C/S端,WebService
0
投稿

猜你喜欢

  • 在mybatis中使用mapper进行if条件判断

    2023-08-01 08:09:34
  • Java Jedis NOAUTH Authentication required问题解决方法

    2023-08-19 14:09:47
  • Java中的关键字_动力节点Java学院整理

    2022-07-28 06:38:29
  • C#实现简易计算器

    2021-12-10 03:33:26
  • java自定义序列化的具体使用

    2022-02-06 06:27:12
  • Android注解基础介绍快速入门与解读

    2023-04-30 22:32:19
  • java基础的详细了解第七天

    2023-02-01 12:06:26
  • C++ 异常处理 catch(...)介绍

    2023-06-24 05:35:32
  • 基于C#的UDP协议的同步通信实现代码

    2023-11-14 09:13:58
  • Android实现网易云推荐歌单界面

    2022-01-15 16:36:48
  • Java使用BigDecimal进行运算封装的实际案例

    2023-06-20 02:22:26
  • java开发ServiceLoader实现机制及SPI应用

    2022-12-24 09:55:05
  • springboot+swagger2.10.5+mybatis-plus 入门详解

    2023-03-15 01:58:38
  • javaweb实现在线支付功能

    2022-02-08 19:17:34
  • Android手机开发设计之记事本功能

    2023-12-10 21:47:00
  • 解决Java中的java.io.IOException: Broken pipe问题

    2022-01-24 00:40:34
  • Cocos2d-x的内存管理总结

    2022-08-31 04:16:02
  • Java如何在临界区中避免竞态条件

    2022-11-02 09:39:29
  • C#实现去除Strings中空格的方法

    2023-12-01 10:54:10
  • Windows系统中使用C#读取文本文件内容的小示例

    2023-05-05 20:27:08
  • asp之家 软件编程 m.aspxhome.com