C#实现带自定义字段的WSSE安全SOAP请求时遇运行时错误
解决WSSE UsernameToken带自定义字段的SOAP服务调用问题
你现在遇到的是调用带WSSE身份验证(还包含自定义字段CustomField)的SOAP服务时的两个核心问题:一是WSE代理类调用时的空引用错误,二是服务端返回的SoapHeaderException(MustUnderstand头未被处理),同时Blue Prism原生不支持SOAP头,给实现增加了难度。先看你提供的示例SOAP请求:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:kas="http://webservice.com"> <soapenv:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken> <wsse:Username>abc</wsse:Username> <wsse:CustomField>123</wsse:CustomField> </wsse:UsernameToken> </wsse:Security> </soapenv:Header> <soapenv:Body> <kas:method1> <!--Optional:--> <method1> <!--Optional:--> <queryNo>12345678901</queryNo> </method1> </kas:method1> </soapenv:Body> </soapenv:Envelope>
你用WSE 3.0生成代理类后,遇到的具体错误:
- Blue Prism中运行时出现
Object reference not set to an instance of an object.,定位到mWebService.RequestSoapContext.Security.Tokens.Add(token);这行 - Visual Studio控制台程序中出现
SoapHeaderException: MustUnderstand headers:[{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security] are not understood
错误原因分析
- 空引用错误:
RequestSoapContext未被初始化,通常是因为WSE的配置未正确启用,导致代理类没有创建SOAP上下文对象;另外,WSE默认的UsernameToken类不包含服务端要求的CustomField,这也可能引发后续异常。 - MustUnderstand头错误:服务端要求
Security头必须被客户端正确处理,但你的代理类没有启用WSE的SOAP扩展来识别WSSE头,导致框架无法解析这个头从而抛出异常。 - Blue Prism限制:Blue Prism原生SOAP工具不支持自定义SOAP头,必须通过自定义代码构造完整请求。
解决方案
一、修正WSE代理类的配置(VS环境)
确保项目的app.config/web.config中添加WSE 3.0的必要配置,启用SOAP扩展:
<configuration> <configSections> <section name="microsoft.web.services3" type="Microsoft.Web.Services3.Configuration.WebServicesConfiguration, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </configSections> <microsoft.web.services3> <security> <tokenIssuer> <add URI="http://webservice.com" /> </tokenIssuer> </security> <soapServerProtocolFactory type="Microsoft.Web.Services3.WseProtocolFactory, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </microsoft.web.services3> <system.web> <webServices> <soapExtensionImporterTypes> <add type="Microsoft.Web.Services3.Description.WseExtensionImporter, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </soapExtensionImporterTypes> <soapServerProtocolFactory type="Microsoft.Web.Services3.WseProtocolFactory, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </webServices> </system.web> </configuration>
二、自定义UsernameToken类以支持CustomField
WSE默认的UsernameToken不包含CustomField,需要继承并重写方法添加该字段:
using System.Xml; using Microsoft.Web.Services3.Security; using Microsoft.Web.Services3.Security.Tokens; public class CustomUsernameToken : UsernameToken { public string CustomField { get; set; } public CustomUsernameToken(string username, string customField, PasswordOption passwordOption) : base(username, string.Empty, passwordOption) // 你的示例中无Password字段,故传空 { CustomField = customField; } protected override void WriteTokenXml(XmlWriter writer) { base.WriteTokenXml(writer); // 写入自定义字段 writer.WriteStartElement("CustomField", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); writer.WriteString(CustomField); writer.WriteEndElement(); } }
三、修正VS控制台程序的调用代码
使用自定义CustomUsernameToken,确保SOAP上下文正确初始化:
// 初始化代理类 var mWebService = new YourWebServiceProxy(); // 确保WSE上下文已启用(配置正确后通常无需手动初始化) if (mWebService.RequestSoapContext == null) { mWebService.RequestSoapContext = new SoapContext(); } // 创建自定义身份令牌 var customToken = new CustomUsernameToken("abc", "123", PasswordOption.SendPlainText); mWebService.RequestSoapContext.Security.Tokens.Add(customToken); // 构造请求参数 queryNoSorguType q = new queryNoSorguType(); q.queryNo = "12345678901"; // 调用服务 ResultType[] r = mWebService.documentQuerybyQueryNo(q); // 处理结果到DataTable System.Data.DataTable outputDataTable = new System.Data.DataTable(); foreach (var result in r) { var row = outputDataTable.NewRow(); row["field1"] = result.Field1; // 替换为ResultType的实际字段名 outputDataTable.Rows.Add(row); } var output = outputDataTable;
四、Blue Prism中的实现方案
由于Blue Prism原生不支持SOAP头,推荐用**C#代码阶段(Code Stage)**直接构造完整SOAP请求并发送HTTP请求:
- 创建Code Stage,设置输入参数:
username(文本)、customField(文本)、queryNo(文本)、serviceUrl(文本);输出参数:responseXml(文本)、errorMessage(文本)。 - 在Code Stage中编写以下代码:
using System; using System.Net; using System.Text; using System.Xml; public class Script { public static void Main(string username, string customField, string queryNo, string serviceUrl, out string responseXml, out string errorMessage) { responseXml = string.Empty; errorMessage = string.Empty; try { // 构造完整SOAP请求 string soapRequest = $@" <soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:kas=""http://webservice.com""> <soapenv:Header> <wsse:Security xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""> <wsse:UsernameToken> <wsse:Username>{username}</wsse:Username> <wsse:CustomField>{customField}</wsse:CustomField> </wsse:UsernameToken> </wsse:Security> </soapenv:Header> <soapenv:Body> <kas:method1> <method1> <queryNo>{queryNo}</queryNo> </method1> </kas:method1> </soapenv:Body> </soapenv:Envelope>"; // 发送HTTP请求 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serviceUrl); request.Method = "POST"; request.ContentType = "text/xml;charset=utf-8"; request.Headers.Add("SOAPAction", "\"http://webservice.com/method1\""); // 替换为实际SOAPAction // 写入请求内容 using (var stream = request.GetRequestStream()) { byte[] buffer = Encoding.UTF8.GetBytes(soapRequest); stream.Write(buffer, 0, buffer.Length); } // 获取响应 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { using (var reader = new XmlTextReader(response.GetResponseStream())) { responseXml = reader.ReadOuterXml(); } } } catch (Exception ex) { errorMessage = ex.ToString(); } } }
- 配置输入输出映射后,即可在Blue Prism流程中调用该Code Stage,后续可使用Blue Prism的XML工具解析
responseXml得到结果。
内容的提问来源于stack exchange,提问作者Vesnog
相关产品推荐
相关产品推荐

