简体   繁体   English

在SOAP请求中使用自定义字段实现WSSE安全标头时,C#运行时错误

[英]C# Runtime Error when implementing WSSE Security Headers with custom fields in SOAP request

I am trying to send a SOAP request to a web service that uses WSSE and UsernameToken for authentication. 我正在尝试向使用WSSE和UsernameToken进行身份验证的Web服务发送SOAP请求 The sample query is as follows (masking confidential data): 示例查询如下(屏蔽机密数据):

<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> 

I have generated a proxy class using WSE 3.0 and the problem is that I get the error: "Object reference not set to an instance of an object." 我已经使用WSE 3.0生成了一个代理类,问题是出现错误:“对象引用未设置为对象的实例。” The problematic part of my C# code is below: 我的C#代码中有问题的部分如下:

queryNoSorguType q = new queryNoSorguType();
string query_parameter = query_no;
q.queryNo = query_parameter;

ResultType[] r = new ResultType[10];

UsernameToken token = new UsernameToken("abc", "123",PasswordOption.SendPlainText);
//mWebService.SetClientCredential<UsernameToken>(token);
//Policy webServiceClientPolicy = new Policy();
mWebService.RequestSoapContext.Security.Tokens.Add(token);
//mWebService.SetPolicy(webServiceClientPolicy);

//r = mWebService.documentQuerybyQueryNo(q);

System.Data.DataTable outputDataTable = new System.Data.DataTable();
//System.Data.DataRow outRow = outputDataTable.Rows.Add();
//outRow["field1"] = r;
output = outputDataTable;

I located the problematic part by systemically commenting out portions of my code. 通过系统地注释掉我的代码部分,我找到了有问题的部分。 I am quite unfamiliar with web services, C# and I am actually implementing this in Blue Prism . 我对Web服务非常不熟悉,C#实际上是在Blue Prism中实现的 Although this program works with SOAP web services out of the box, unfortunately it does not natively support SOAP headers. 尽管该程序可以立即使用SOAP Web服务,但是不幸的是,它本身并不支持SOAP标头。

The SOAP request works fine in SOAP UI and there are no compiler errors in Blue Prism. SOAP请求在SOAP UI中工作正常,并且在Blue Prism中没有编译器错误。 I tried adding the headers as instructed in the manual and on the web, but it did not work. 我尝试按照手册和网络上的说明添加标题,但没有用。 I would appreciate it if you could point me in the right direction. 如果您能指出正确的方向,我将不胜感激。

EDIT After writing, compiling a console application in Visual Studio 2017 I get the following error. 编辑编写,在Visual Studio 2017中编译控制台应用程序后,出现以下错误。 As far as I understand it does not have the definitions for the headers. 据我了解,它没有标题的定义。

Unhandled Exception: System.Web.Services.Protocols.SoapHeaderException: MustUnderstand headers:[{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security] are not understood
   at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
   at WebService.queryByQueryNo(queryNoQueryType queryByQueryNo1) in C:\Users\user\source\repos\ConsoleApp1\ConsoleApp1\Web References\WebService\Reference.cs:line 1533
   at ConsoleApp1.Program.Main(String[] args) in C:\Users\user\source\repos\ConsoleApp1\ConsoleApp1\Program.cs:line 33

I think is the xml structure punctually the headers when you use 我认为是xml结构按时使用标头

<wsse:Security wsse is not defined, I know you defined in the same line but why not try put it on the document, something like this <wsse:Security wsse没有定义,我知道您在同一行中定义了,但是为什么不尝试将其放在文档中,类似这样

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:kas="http://webservice.com" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
   <soapenv:Header>
      <wsse:Security>
         <wsse:UsernameToken>
            <wsse:Username>abc</wsse:Username>
            <wsse:CustomField>123</wsse:CustomField>
         </wsse:UsernameToken>
      </wsse:Security>
   </soapenv:Header>

I decided to utilize a different method and quit trying to use a proxy class for the time being as there were problems associated with it. 我决定使用另一种方法,由于存在相关问题,因此暂时不尝试使用代理类。 Making use of the answers on this link: Client to send SOAP request and receive response I came up with my own solution after some customization. 利用此链接上的答案: 客户端发送SOAP请求并接收响应我经过一些自定义后提出了自己的解决方案。

However, I still wonder how to proceed in order to make it work using wrapper classes defined by Visual Studio or WSE 3.0. 但是,我仍然想知道如何继续使用Visual Studio或WSE 3.0定义的包装器类使其工作。 After writing the code and testing it in Visual Studio it was pretty easy to port it into Blue Prism. 在编写代码并在Visual Studio中对其进行测试之后,将其移植到Blue Prism中非常容易。

using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Net;
using System.IO;
using System.Xml.Linq;
namespace WebService
{
    class Program
    {
        /// <summary>
        /// Execute a Soap WebService call
        /// </summary>
        public static string Execute(string queryNo)
        {
            HttpWebRequest request = CreateWebRequest();
            XmlDocument soapEnvelopeXml = new XmlDocument();
            soapEnvelopeXml.LoadXml(@"<?xml version=""1.0"" encoding=""utf-8""?>
                <soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:customNAMESPACE=""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>USER</wsse:Username>
                            <wsse:CustomField>CODE</wsse:CustomField>
                        </wsse:UsernameToken>
                     </wsse:Security>
                  </soapenv:Header>
                  <soapenv:Body>
                     <customNAMESPACE:QueryByQueryNo>
                        <!--Optional:-->
                        <QueryByQueryNo>
                            <!--Optional:-->
                            <queryNo>" + queryNo + @"</queryNo>
                        </QueryByQueryNo>
                      </customNAMESPACE:QueryByQueryNo>
                  </soapenv:Body>
                </soapenv:Envelope>");

            using (Stream stream = request.GetRequestStream())
            {
                soapEnvelopeXml.Save(stream);
            }

            using (WebResponse response = request.GetResponse())
            {
                using (StreamReader rd = new StreamReader(response.GetResponseStream()))
                {
                    string soapResult = rd.ReadToEnd();
                    Console.WriteLine(soapResult);
                    return soapResult;
                }
            }
        }
        /// <summary>
        /// Create a soap webrequest to [Url]
        /// </summary>
        /// <returns></returns>
        public static HttpWebRequest CreateWebRequest()
        {
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(@"https://webservice.com/webservice?wsdl");
            webRequest.Headers.Add(@"SOAP:Action");
            webRequest.ContentType = "text/xml;charset=\"utf-8\"";
            webRequest.Accept = "text/xml";
            webRequest.Method = "POST";
            return webRequest;
        }
        static void Main(string[] args)
        {
            if (args.Length == 0 || args.Length > 1)
            {
                System.Console.WriteLine("Please provide a query no");
                System.Console.WriteLine("Usage: WebService.exe 3523423333");
                return;
            }

            string output, XMLresponse;
            try
            {
                XMLresponse = Execute(args[0]);
                output = "Successful query";
                XmlDocument xml = new XmlDocument();
                xml.LoadXml(XMLresponse);  // suppose that str string contains the XML data. You may load XML data from a file too.
                XmlNodeList resultCodeList = xml.GetElementsByTagName("resultCode");
                XmlNodeList resultNoList = xml.GetElementsByTagName("resultNo");
                int i = 0;
                var OutputTable = new DataTable();
                OutputTable.Columns.Add("Result Code", typeof(string));
                OutputTable.Columns.Add("Result No", typeof(string));
                foreach (XmlNode xn in resultCodeList)
                {
                    Console.WriteLine(resultCodeList[i].InnerText + "  " + resultNoList[i].InnerText);
                    OutputTable.Rows.Add(resultCodeList[i].InnerText, resultNoList[i].InnerText);
                    i++;
                }

            }
            catch (System.Net.WebException exc)
            {
                Console.WriteLine("HTTP POST request failed!");
                output = "!!!HTTP POST request failed!!!";
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM