Заголовки SOAP принудительно устанавливаются с mustunderstand = 1 даже при вызове метода beforesendrequest - PullRequest
0 голосов
/ 04 декабря 2018

Я скачал пример реализации C # с NVMS, чтобы понять, как реализовать свои веб-сервисы.Он использует запросы SOAP для вызова различных сервисов.В исходном коде есть внутренний класс, реализующий IEndpointBehavior и IClientMessageInspector, а в BeforeSendRequest они очищали заголовки SOAP, но, судя по полученному ответу, у окончательного запроса все еще есть заголовки.Я пробовал оба запроса (с заголовками и без заголовков), которые печатаются на консоли в SOAPUI, и запрос без заголовка работает, в то время как другой получает то же сообщение, которое я получаю в самом приложении C #.

Вот класс:

internal class CustomMessageInspector : IEndpointBehavior, IClientMessageInspector
{
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(this);
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }

    /*public void BeforeSendReply(ref Message reply, object correlationState)
    {
        reply.Headers.Clear();
    }*/

    //add using directive Message = System.ServiceModel.Channels.Message;
    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        // WORKAROUND for WCF-Exception "The MessageHeader is already understood" 
        // (Note: The message still gets validated)
        reply.Headers.Clear();
        Console.WriteLine("received Response:");
        Console.WriteLine("{0}\r\n", reply);
    }

    /// <summary>
    /// Shows the sent message with and without SOAP-Header
    /// </summary>
    /// <param name="request"></param>
    /// <param name="channel"></param>
    /// <returns></returns>
    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        // Fait la même chose que le clear, mais ne fonctione pas non plus...
        /*request.Headers.ReplyTo = null;
        request.Headers.Action = null;
        request.Headers.MessageId = null;*/
        Console.WriteLine("original Request:");
        Console.WriteLine("{0}\r\n", request);
        // Ne semble pas fonctionner, la requête est envoyée avec les headers...
        request.Headers.Clear();

        Console.WriteLine("without Header Request:");
        Console.WriteLine("{0}\r\n", request);

        return null;
    }
}

"request.Headers.Clear ();"линия должна работать здесь.Аргумент запроса передается по ссылке, поэтому он должен очистить заголовки от исходного объекта.Но вот результат, который я получаю:

received Response:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <s:Header xmlns:s="http://www.w3.org/2003/05/soap-envelope" />
  <soap:Body>
    <soap:Fault>
      <soap:Code>
        <soap:Value>soap:MustUnderstand</soap:Value>
      </soap:Code>
      <soap:Reason>
        <soap:Text xml:lang="en">MustUnderstand headers: [{http://www.w3.org/2005/08/addressing}To] are not understood.</soap:Text>
      </soap:Reason>
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

Вот 2 запроса (с заголовками и без них, как напечатано методом beforesendrequest):

original Request:
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action s:mustUnderstand="1">ns:G110RequestMessage</a:Action>
    <a:MessageID>urn:uuid:405c0e93-f39d-4d8b-bef8-72cf82f88203</a:MessageID>
    <a:ReplyTo>
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <G110Request xmlns="urn:wsdltypes.nmvs.eu:v3.0">
      <Header xmlns="urn:types.nmvs.eu:v3.0">
        <Auth>
          <ClientLoginId>ABC</ClientLoginId>
          <UserId>test123</UserId>
          <Password>123456</Password>
        </Auth>
        <UserSoftware d5p1:name="Test Soft" d5p1:supplier="Comp Any" d5p1:version="V2" xmlns:d5p1="urn:types.nmvs.eu:v3.0" />
        <Transaction>
          <ClientTrxId>7775559966aaa</ClientTrxId>
          <Language>eng</Language>
        </Transaction>
      </Header>
      <Body xmlns="urn:types.nmvs.eu:v3.0">
        <Product>
          <ProductCode d6p1:scheme="GTIN" xmlns:d6p1="urn:types.nmvs.eu:v3.0">PK001C854A8EE536949</ProductCode>
          <Batch>
            <Id>TESTA1596337CF</Id>
            <ExpDate>231130</ExpDate>
          </Batch>
        </Product>
        <Pack d5p1:sn="PK001C854A8EE536949" xmlns:d5p1="urn:types.nmvs.eu:v3.0" />
      </Body>
    </G110Request>
  </s:Body>
</s:Envelope>

without Header Request:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header />
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <G110Request xmlns="urn:wsdltypes.nmvs.eu:v3.0">
      <Header xmlns="urn:types.nmvs.eu:v3.0">
        <Auth>
          <ClientLoginId>ABC</ClientLoginId>
          <UserId>test123</UserId>
          <Password>123456</Password>
        </Auth>
        <UserSoftware d5p1:name="Test Soft" d5p1:supplier="Comp Any" d5p1:version="V2" xmlns:d5p1="urn:types.nmvs.eu:v3.0" />
        <Transaction>
          <ClientTrxId>7775559966aaa</ClientTrxId>
          <Language>eng</Language>
        </Transaction>
      </Header>
      <Body xmlns="urn:types.nmvs.eu:v3.0">
        <Product>
          <ProductCode d6p1:scheme="GTIN" xmlns:d6p1="urn:types.nmvs.eu:v3.0">PK001C854A8EE536949</ProductCode>
          <Batch>
            <Id>TESTA1596337CF</Id>
            <ExpDate>231130</ExpDate>
          </Batch>
        </Product>
        <Pack d5p1:sn="PK001C854A8EE536949" xmlns:d5p1="urn:types.nmvs.eu:v3.0" />
      </Body>
    </G110Request>
  </s:Body>
</s:Envelope>

Я пытался изменить атрибут mustUnderstand, но не могу найти, где его изменить.

Ответы [ 2 ]

0 голосов
/ 07 декабря 2018

Как предлагает Марк, решение состоит в том, чтобы создать CustomBinding и изменить AdressingVersion на None.

Вот код, который я использовал, основанный на приведенном выше, но с необходимой доработкой, которую мне пришлось сделать, чтобызаставить меня работать.

       //add using directive System.ServiceModel;
        //Defines a secure binding with certificate authentication
        WSHttpBinding binding = new WSHttpBinding();
        binding.Security.Mode = SecurityMode.Transport;
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

        // create a new binding based on the existing binding
        var customTransportSecurityBinding = new CustomBinding(binding);
        var customTransportSecurityBindingCopy = new CustomBinding(binding);

        // locate the TextMessageEncodingBindingElement - that's the party guilty of the inclusion of the "To"

        foreach(BindingElement element in customTransportSecurityBinding.Elements)
        {
            // and replace it with a version with no addressing
            // replace {Soap12 (http://www.w3.org/2003/05/soap-envelope) Addressing10 (http://www.w3.org/2005/08/addressing)}
            //    with {Soap12 (http://www.w3.org/2003/05/soap-envelope) AddressingNone (http://schemas.microsoft.com/ws/2005/05/addressing/none)}
            int index = customTransportSecurityBinding.Elements.IndexOf(element);

            if (element is TextMessageEncodingBindingElement)
            {
                var textBindingElement = new TextMessageEncodingBindingElement
                {
                    MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None)
                };

                customTransportSecurityBindingCopy.Elements[index] = textBindingElement;
            }
        }

        customTransportSecurityBinding = customTransportSecurityBindingCopy;
        customTransportSecurityBindingCopy = null;

        //Creates ServiceClient, attach transport-binding, Endpoint and the loaded certificate
        SinglePackServicesClient service = new SinglePackServicesClient(customTransportSecurityBinding, new EndpointAddress(EndPoint));
0 голосов
/ 06 декабря 2018

Ну, после более чем одного дня поиска у меня есть решение.На самом деле Николас Джанноне предоставил здесь весь необходимый код WSHttpBinding в .NetStandard или .NET core Ниже приведена функция SinglePackPing из примера C # NMVS, модифицированного для работы с песочницей и API V3.

public static Boolean SinglePackPing( MyConfig myConfig, String pingString )
{
    Boolean ok = false;

    string endPoint = myConfig.SinglePackServicesEndPoint;

    //Defines a secure binding with certificate authentication
    WSHttpBinding binding = new WSHttpBinding();
    binding.Security.Mode = SecurityMode.Transport;
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

    // create a new binding based on the existing binding
    var customTransportSecurityBinding = new CustomBinding( binding );
    // locate the TextMessageEncodingBindingElement - that's the party guilty of the inclusion of the "To"
    var ele = customTransportSecurityBinding.Elements.FirstOrDefault( x=>x is TextMessageEncodingBindingElement );
    if( ele != null )
    {
        // and replace it with a version with no addressing
        // replace {Soap12 (http://www.w3.org/2003/05/soap-envelope) Addressing10 (http://www.w3.org/2005/08/addressing)}
        //    with {Soap12 (http://www.w3.org/2003/05/soap-envelope) AddressingNone (http://schemas.microsoft.com/ws/2005/05/addressing/none)}
        int index = customTransportSecurityBinding.Elements.IndexOf( ele );
        var textBindingElement = new TextMessageEncodingBindingElement
        {
            MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None)
        };
        customTransportSecurityBinding.Elements[index] = textBindingElement;
    }

    //Creates ServiceClient, attach transport-binding, Endpoint and the loaded certificate
    using( SinglePackServicesClient service = new SinglePackServicesClient( customTransportSecurityBinding, new EndpointAddress( endPoint ) ) )
    {
        using( X509Certificate2 cert = new X509Certificate2( myConfig.CertificateFilePath, myConfig.PrivateKeyPassword, X509KeyStorageFlags.PersistKeySet ) )
        {

            //Creates ServiceClient, attach transport-binding, Endpoint and the loaded certificate          
            service.ClientCredentials.ClientCertificate.Certificate = cert;
            service.Endpoint.EndpointBehaviors.Add( new CustomMessageInspector() );
            var bindingTest = service.Endpoint.Binding;

            //Creates PingRequest and set the ping Input
            SinglePackPingRequest ping = new SinglePackPingRequest();
            ping.Input = pingString;

            //Creates PingResponse, result of the request. Displays the response
            SinglePackPingResponse pingResponse = service.PingSinglePack(ping);

            ok = pingResponse.Output == pingString;

            //Displays the response. If the request is successful, the output is equal to the input
            Console.WriteLine( pingResponse.Output );
        }
    }

    return ok;
}

Надеюсь, это поможет вам.Дайте мне знать, как вы поживаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...