一、问题描述
1.1 ESB平台要求
-
ContentType
:application/xml
-
Soap协议版本
:1.1
1.2 提供的 WebService 接口
-
语言
:C# -
目标框架
:.NetFramework 4.6.1
1.3 Postman 测试结果
HTTP Error 415.0 - Unsupported Media Type
服务器无法为请求提供服务,因为不支持该媒体类型。
最可能的原因:
所请求文件的格式已由服务器配置为不可进行下载。
可尝试的操作:
确认所请求文件的格式有效。
Detailed Error Information:
Module | ManagedPipelineHandler | Requested URL | http://localhost:55305/WebService.asmx?op=callBussiness |
Notification | ExecuteRequestHandler | Physical Path | …\ESBWebService.asmx |
Handler | WebServiceHandlerFactory-Integrated-4.0 | Logon Method | 匿名 |
Error Code | 0x00000000 | Logon User | 匿名 |
More Information:
如果服务器因不支持该文件类型而无法为请求提供服务,就会出现此错误。
View more information »
二、问题说明
C# 使用创建的标准WebService 只支持以下ContentType类型
-
SOAP 1.1
:text/xml; charset=utf-8
-
SOAP 1.2
:application/soap+xml; charset=utf-8
-
HTTP POST
:application/x-www-form-urlencoded
综上所述,要想解决此问题,由以下两种途径:
- 与
ESB
平台人员沟通,要求使用WebService
所支持的媒体类型text/xml;
- 自己扩展
SOAP
,拦截application/xml
类型的请求
三、解决方案
3.1 与ESB平台人员沟通,要求使用WebService所支持的媒体类型text/xml;
3.2 自己扩展SOAP,拦截application/xml
类型的请求
要在C#
WebService
启动服务时支持application/xml
文件类型,您可以通过在 WebService
服务代码中添加一个 SOAP
扩展来实现。
3.2.1 扩展 SoapExtensionAttribute
[AttributeUsage(AttributeTargets.Method)]
public class ESBSoapExtensionAttribute : SoapExtensionAttribute
{
private int priority;
public ESBSoapExtensionAttribute()
{
}
public override Type ExtensionType
{
get { return typeof(ESBSoapExtension); }
}
public override int Priority
{
get { return priority; }
set { priority = value; }
}
}
3.2.2 扩展 SoapExtension
在ProcessMessage
中判断ContentType
是不是"application/xml"
,如果是则替换为可以被解析的"text/xml"
public class ESBSoapExtension : SoapExtension
{
public ESBSoapExtension extension;
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
return extension ?? (extension = new ESBSoapExtension());
}
public override object GetInitializer(Type serviceType)
{
return extension ?? (extension = new ESBSoapExtension());
}
public override void Initialize(object initializer)
{
//base.Initialize(initializer);
}
public override void ProcessMessage(SoapMessage message)
{
// 检查请求头Content-Type是否为"application/xml"
try
{
switch (message.Stage)
{
case SoapMessageStage.BeforeDeserialize:
if (message is SoapServerMessage serverMessage && serverMessage.ContentType.Contains("application/xml"))
{
// 设置响应头Content-Type为"application/xml"
serverMessage.ContentType = "text/xml";
}
break;
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
break;
case SoapMessageStage.AfterDeserialize:
// 在反序列化之后进行处理(响应阶段)
break;
default:
break;
}
}
catch(Exception exp)
{
}
}
}
3.2.3 在方法callBussiness
上注入扩展
[WebMethod(Description = "调用业务")]
[ESBSoapExtension(Priority =1)]
public string callBussiness(string message)
{
return message;
}
** 完整代码**
using System;
using System.IO;
using System.Text;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml;
using System.Xml.Serialization;
using Rss_WebServer.code;
[AttributeUsage(AttributeTargets.Method)]
public class ESBSoapExtensionAttribute : SoapExtensionAttribute
{
private int priority;
public ESBSoapExtensionAttribute()
{
}
public override Type ExtensionType
{
get { return typeof(ESBSoapExtension); }
}
public override int Priority
{
get { return priority; }
set { priority = value; }
}
}
public class ESBSoapExtension : SoapExtension
{
public ESBSoapExtension extension;
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
return extension ?? (extension = new ESBSoapExtension());
}
public override object GetInitializer(Type serviceType)
{
return extension ?? (extension = new ESBSoapExtension());
}
public override void Initialize(object initializer)
{
//base.Initialize(initializer);
}
public override void ProcessMessage(SoapMessage message)
{
// 检查请求头Content-Type是否为"application/xml"
try
{
switch (message.Stage)
{
case SoapMessageStage.BeforeDeserialize:
if (message is SoapServerMessage serverMessage && serverMessage.ContentType.Contains("application/xml"))
{
// 设置响应头Content-Type为"application/xml"
serverMessage.ContentType = "text/xml";
}
break;
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
break;
case SoapMessageStage.AfterDeserialize:
// 在反序列化之后进行处理(响应阶段)
break;
default:
break;
}
}
catch(Exception exp)
{
}
}
}
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
{
public override object GetService(Type service)
{
return base.GetService(service);
}
public WebService()
{
//this.Application.sa
this.Context.Request.ContentType = "application/xml";
}
[WebMethod(Description = "调用业务")]
[ESBSoapExtension(Priority =1)]
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;
}
}
}
}