一、问题说明
1.1 问题描述
使用C#
搭建WebService
接口,并按照ESB平台
人员的要求,将命名空间改为"http://esb.webservice"
,使用Postman
+ESB平台
人员提供的入参示例进行测试时,callBussiness
接口参数message
始终为null
。
以下是ESB平台提供的模版
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:esb="http://esb.webservice">
<soapenv:Header/>
<soapenv:Body>
<esb:callBussiness>
<!--Optional:-->
<message>
<![CDATA[...]]>
</message>
</esb:callBussiness>
</soapenv:Body>
</soapenv:Envelope>
1.2 C# WebService代码
using System;
using System.IO;
using System.Text;
using System.Web.Services;
using System.Xml;
using System.Xml.Serialization;
using Rss_WebServer.code;
namespace ESB
{
/// <summary>
/// WebService 的摘要说明
/// </summary>
[WebService(Namespace = "http://esb.webservice")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
// [System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService
{
[WebMethod(Description = "调用业务")]
public string callBussiness(string message)
{
return message;
}
}
}
1.3 Postman 测试参数
-
POST
http://localhost:55305/WebService.asmx?op=callBussiness - Headers
KEY | VALUE | DESCRIPTION |
---|---|---|
Content-Type | text/xml; charset=utf-8 | |
SOAPAction | “http://esb.webservice/callBussiness” |
- Body
- raw
XML(text/xml)
- raw
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:esb="http://esb.webservice">
<soapenv:Header/>
<soapenv:Body>
<esb:callBussiness>
<!--Optional:-->
<message>
<![CDATA[<root><author>少莫千华</author><email>370763160@qq.com</email></root>]]>
</message>
</esb:callBussiness>
</soapenv:Body>
</soapenv:Envelope>
二、问题分析
根本问题是ESB平台
提供的参数模版并没有完全按照标准的WebService协议进行编写,导致使用官方搭建的WebService接口无法正常的解析参数,所以要想解决此问题,有两个途径:
- 与ESB平台人员沟通,要求其标准化参数模版
- 自己重新解构
WebService
参数
三、解决方案
3.1 与ESB平台人员沟通,要求其标准化参数模版
3.1.1 标准模版 - 使用命名空间缩写
对callBussiness
接口的message
参数添加命名空间缩写esb
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:esb="http://esb.webservice">
<soapenv:Header/>
<soapenv:Body>
<esb:callBussiness>
<!--Optional:-->
<esb:message>
<![CDATA[...]]>
</esb:message>
</esb:callBussiness>
</soapenv:Body>
</soapenv:Envelope>
3.1.1 标准模版 - 使用完整的命名空间
对callBussiness
接口的使用完整的命名空间<callBussiness xmlns="http://esb.webservice">
。
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<callBussiness xmlns="http://esb.webservice">
<!--Optional:-->
<message>
<![CDATA[...]]>
</message>
</callBussiness>
</soapenv:Body>
</soapenv:Envelope>
3.2 自己重新解构WebService
参数
从请求对象base.Context.Request
中重新获取所有Body
内容(InputStream
),然后再进行自定义解析。
注:因为是搭建的标准的WebService
接口Body
内容(InputStream
)在进去函数内部前已经被SOAP协议
解析过一次,所以InputStream
的起始内容位置Position
指向数据流的结尾,所以在读取之前,先要将InputStream
的起始内容位置Position
设置为0
,否则读取的内容为空('')
using System;
using System.IO;
using System.Text;
using System.Web.Services;
using System.Xml;
using System.Xml.Serialization;
using Rss_WebServer.code;
namespace ESB
{
/// <summary>
/// WebService 的摘要说明
/// </summary>
[WebService(Namespace = "http://esb.webservice")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
// [System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService
{
[WebMethod(Description = "调用业务")]
public string callBussiness(string message)
{
try
{
if (string.IsNullOrEmpty(message))
{
message = WebServiceAnalysis(base.Context.Request, nameof(message));
}
return message;
}
catch(Exception exp)
{
return exp.Message;
}
}
/// <summary>
/// 重新解析 WebService
/// </summary>
/// <param name="request"></param>
/// <param name="name"></param>
/// <returns></returns>
private string WebServiceAnalysis(System.Web.HttpRequest request,string name)
{
try
{
if(request.ContentLength == 0)
{
throw new Exception($"Body(xml数据) 无数据");
}
// 获取请求内容
Stream inputStream = request.InputStream;
// 重新获取内容
inputStream.Position = 0;
// 读取请求主体内容
using (StreamReader reader = new StreamReader(inputStream, Encoding.UTF8))
{
string requestBody = reader.ReadToEnd();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(requestBody);
XmlNode strNode = xmlDoc.SelectSingleNode($"//{name}");
if (strNode != null)
{
return strNode.InnerText;
}
else
{
throw new Exception($"未在Body(xml数据)找到{name}节点");
}
}
}
catch(Exception exp)
{
throw exp;
}
}
}
}