Получение данных из веб-службы с адресацией ws

У меня есть веб-сервис на клиентском сайте, из которого мне нужно сообщить.

Локально я подражал службе, используя предоставленные wsdls, и смог сообщить об этом. Однако теперь, указывая на клиентский сайт, я не могу получить доступ к данным, так как служба требует включения заголовков адресации ws.

Вебсервис ожидает следующее:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:add="http://www.w3.org/2005/08/addressing" xmlns:ns="CustomerNamespace" xmlns:sch="Schema.xsd">
   <soapenv:Header>
      <add:From>
         <add:Address>Something</add:Address>
         <add:ReferenceParameters>
            <ns:TransactionGroupID>SomeOtherThing</ns:TransactionGroupID>
            <ns:SenderID>911</ns:SenderID>
         </add:ReferenceParameters>
      </add:From>
      <add:Action>Request</add:Action>
      <add:MessageID>TestGUID</add:MessageID>
   </soapenv:Header>
   <soapenv:Body>
      <sch:Request>
         <sch:SearchCustomerSystem>SystemXYZ</sch:SearchCustomerSystem>
          <sch:ServiceID>999999999999</sch:ServiceID>
      </sch:Request>
   </soapenv:Body>
</soapenv:Envelope>

В настоящее время я могу получить SSRS для создания ниже:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <Request xmlns="Schema.xsd">
      <ServiceID>
          999999999999
        </ServiceID>
    </Request>
  </soap:Body>
</soap:Envelope>

Помимо создания пользовательского расширения данных (чего я бы предпочел избежать), есть ли способ получить заголовки адресации ws в запросе?

Ответ 1

Следующий фрагмент является частью нашего WSDL, который может быть полезен, если у вас есть возможность изменить WSDL. Скорее всего, вам понадобится немного пространства имен, особенно связанные с адресацией. Пространство имен "wsaw" - это тот, который используется в наших атрибутах Action, которые живут на wsdl: входные атрибуты по пути wsdl: portType → wsdl: operation.

  <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="OurTargetNamespaceHere" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" name="OurServiceNameHere" targetNamespace="OurTargetNamespaceHere">
  <wsp:Policy wsu:Id="OurCustomPolicy_policy">
    <wsp:ExactlyOne>
      <wsp:All>
        <sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
          <wsp:Policy>
            <sp:TransportToken>
              <wsp:Policy>
                <sp:HttpsToken RequireClientCertificate="false"/>
              </wsp:Policy>
            </sp:TransportToken>
            <sp:AlgorithmSuite>
              <wsp:Policy>
                <sp:Basic256/>
              </wsp:Policy>
            </sp:AlgorithmSuite>
            <sp:Layout>
              <wsp:Policy>
                <sp:Strict/>
              </wsp:Policy>
            </sp:Layout>
          </wsp:Policy>
        </sp:TransportBinding>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

Ответ 2

В этом примере я буду использовать С#

Используя ожидаемый огибающий в вашем примере, были получены следующие классы.

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://schemas.xmlsoap.org/soap/envelope/", IsNullable = false)]
public partial class Envelope {
    /// <remarks/>
    public EnvelopeHeader Header { get; set; }
    /// <remarks/>
    public EnvelopeBody Body { get; set; }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public partial class EnvelopeHeader {
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.w3.org/2005/08/addressing")]
    public From From { get; set; }
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.w3.org/2005/08/addressing")]
    public string Action { get; set; }
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.w3.org/2005/08/addressing")]
    public string MessageID { get; set; }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/08/addressing")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.w3.org/2005/08/addressing", IsNullable = false)]
public partial class From {
    /// <remarks/>
    public string Address { get; set; }
    /// <remarks/>
    public FromReferenceParameters ReferenceParameters { get; set; }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/08/addressing")]
public partial class FromReferenceParameters {
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "CustomerNamespace")]
    public string TransactionGroupID { get; set; }
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "CustomerNamespace")]
    public ushort SenderID { get; set; }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public partial class EnvelopeBody {
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "Schema.xsd")]
    public Request Request { get; set; }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "Schema.xsd")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "Schema.xsd", IsNullable = false)]
public partial class Request {
    /// <remarks/>
    public string SearchCustomerSystem { get; set; }
    /// <remarks/>
    public ulong ServiceID { get; set; }
}

Используя вышеуказанные классы, для

будет использоваться следующий Unit Test

способ получить заголовки адресации ws в запросе

[TestClass]
public class MyTestClass {
    [TestMethod]
    public void _ws_addressing_headers_into_the_request() {

        var xmlWithBodyOnly = GetEnvelopFromSSRS();
        var header = BuildHeader();
        var result = AppendHeader(xmlWithBodyOnly, header);

    }

    private static EnvelopeHeader BuildHeader() {
        var header = new EnvelopeHeader {
            From = new From {
                Address = "Someting",
                ReferenceParameters = new FromReferenceParameters {
                    SenderID = 911,
                    TransactionGroupID = "SomeOtherThing"
                }
            },
            Action = "Request",
            MessageID = "SomeGuid"
        };
        return header;
    }

    private static string GetEnvelopFromSSRS() {
        var xmlWithBodyOnly = @"
<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>
  <soap:Body>
    <Request xmlns='Schema.xsd'>
      <ServiceID>
          999999999999
        </ServiceID>
    </Request>
  </soap:Body>
</soap:Envelope>";
        return xmlWithBodyOnly;
    }

    private string AppendHeader(string xml, EnvelopeHeader header) {
        var result = string.Empty;
        // convert string to stream
        var data = Encoding.UTF8.GetBytes(xml);
        using (var inStream = new MemoryStream(data)) {
            // Create an instance of the XmlSerializer specifying type and namespace.
            var serializer = new XmlSerializer(typeof(Envelope));
            //Deseiralize XML to something we can work with
            var envelope = (Envelope)serializer.Deserialize(inStream);
            if (envelope != null) {
                //Append the header
                envelope.Header = header;
                //Serialize the envelope back to XML
                using (var outStream = new MemoryStream()) {
                    serializer.Serialize(outStream, envelope);
                    result = Encoding.UTF8.GetString(outStream.ToArray());
                }
            }
        }
        return result;
    }
}

Объяснение.

 var xmlWithBodyOnly = GetEnvelopFromSSRS();

имитирует получение того, что вы смогли произвести через SSRS, на основе примера, приведенного в вашем исходном вопросе.

 var header = BuildHeader();

Используя производные классы, вы можете легко создавать и заполнять необходимые свойства для своего заголовка, как вы считаете нужным

private static EnvelopeHeader BuildHeader() {
    var header = new EnvelopeHeader {
        From = new From {
            Address = "Someting",
            ReferenceParameters = new FromReferenceParameters {
                SenderID = 911,
                TransactionGroupID = "SomeOtherThing"
            }
        },
        Action = "Request",
        MessageID = "SomeGuid"
    };
    return header;
}

Теперь о мясе дела.

var result = AppendHeader(xmlWithBodyOnly, header);

Как только у вас есть конверт и заголовок, вы теперь готовы добавить заголовок адресации ws к запросу

private string AppendHeader(string xml, EnvelopeHeader header) {
    var result = string.Empty;
    // convert string to stream
    var data = Encoding.UTF8.GetBytes(xml);
    using (var inStream = new MemoryStream(data)) {
        // Create an instance of the XmlSerializer specifying type and namespace.
        var serializer = new XmlSerializer(typeof(Envelope));
        //Deseiralize XML to something we can work with
        var envelope = (Envelope)serializer.Deserialize(inStream);
        if (envelope != null) {
            //Append the header
            envelope.Header = header;
            //Serialize the envelope back to XML
            using (var outStream = new MemoryStream()) {
                serializer.Serialize(outStream, envelope);
                result = Encoding.UTF8.GetString(outStream.ToArray());
            }
        }
    }
    return result;
}

Комментарии в коде объясняют, что было сделано.

В приведенном выше примере, учитывая следующий огибающий

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <Request xmlns="Schema.xsd">
      <ServiceID>
          999999999999
        </ServiceID>
    </Request>
  </soap:Body>
</soap:Envelope>

При использовании в приведенном выше коде выводится следующий вывод.

<?xml version="1.0"?>
<Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/soap/envelope/">
  <Header>
    <From xmlns="http://www.w3.org/2005/08/addressing">
      <Address>Someting</Address>
      <ReferenceParameters>
        <TransactionGroupID xmlns="CustomerNamespace">SomeOtherThing</TransactionGroupID>
        <SenderID xmlns="CustomerNamespace">911</SenderID>
      </ReferenceParameters>
    </From>
    <Action xmlns="http://www.w3.org/2005/08/addressing">Request</Action>
    <MessageID xmlns="http://www.w3.org/2005/08/addressing">SomeGuid</MessageID>
  </Header>
  <Body>
    <Request xmlns="Schema.xsd">
      <ServiceID>999999999999</ServiceID>
    </Request>
  </Body>
</Envelope>

Этот вывод теперь можно использовать, чтобы сделать ваш запрос к веб-службе по своему усмотрению. Модели также могут быть изменены по мере необходимости на основе того, что требуется для запроса веб-службы.