Невозможно использовать определение WSDL

Далее следует систематическая разбивка проблемы. [Переписано!]

Код клиента

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

// This is a "sanitized" version of the real deal, of course. In reality I also require to
// sign all incomming and outgoing messages and com. over SSL. The basic model is the same
// though and the sanitized WSDL captures the problem in its minimal form.

namespace MissileDefenseSystem
{
    using MissileDefenseSystemServiceReference;

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var client = new TestPortTypeClient();
                var req = "just do it";
                Console.WriteLine("request>" + req + "<");
                var rsp = client.LaunchMissiles(req);
                Console.WriteLine("response>" + rsp + "<");
            }
            catch (Exception e)
            {
                Console.WriteLine("exception>" + e.Message + "<");
                Console.WriteLine(e.StackTrace);
            }
        }
    }
}

WSDL

<?xml version="1.0" encoding="ISO-8859-1"?>
<definitions targetNamespace="java:bla.bla.bla.bla"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:tns="java:bla.bla.bla.bla"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <types>
    <schema targetNamespace='java:bla.bla.bla.bla' xmlns='http://www.w3.org/2001/XMLSchema'/>
  </types>
  <message name="TestRequest">
    <part name="arg0" type="xsd:string"/>
  </message>
  <message name="TestResponse">
    <part name="return" type="xsd:string"/>
  </message>
  <portType name="TestPortType">
    <operation name="LaunchMissiles">
      <input message="tns:TestRequest"/>
      <output message="tns:TestResponse"/>
    </operation>
    <operation name="AbortMission">
      <input message="tns:TestRequest"/>
      <output message="tns:TestResponse"/>
    </operation>
  </portType>
  <binding name="TestBinding" type="tns:TestPortType">
    <soap:binding style="rpc"  transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="LaunchMissiles">
      <soap:operation soapAction="urn:LaunchMissiles"/>
      <input>
        <soap:body use="encoded" namespace='urn:Test' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </input>
      <output>
        <soap:body use="encoded" namespace='urn:Test' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </output>
    </operation>
    <operation name="AbortMission">
      <soap:operation soapAction="urn:AbortMission"/>
      <input>
        <soap:body use="encoded" namespace='urn:Test' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </input>
      <output>
        <soap:body use="encoded" namespace='urn:Test' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </output>
    </operation>
  </binding>
  <service name="Test">
    <documentation>todo</documentation>
    <port name="TestPort" binding="tns:TestBinding">
      <soap:address location="https://demo.blablablablablabla.com:123/Bla"/>
    </port>
  </service>
</definitions>

След ошибки

request>just do it<
exception>RPC Message LaunchMissilesRequest in operation AbortMission has an invalid body name LaunchMissiles. It must be AbortMission<
   at System.ServiceModel.Description.XmlSerializerOperationBehavior.Reflector.OperationReflector.EnsureMessageInfos()
   at System.ServiceModel.Description.XmlSerializerOperationBehavior.Reflector.EnsureMessageInfos()
   at System.ServiceModel.Description.XmlSerializerOperationBehavior.Reflector.OperationReflector.get_Request()
   at System.ServiceModel.Description.XmlSerializerOperationBehavior.CreateFormatter()
   at System.ServiceModel.Description.XmlSerializerOperationBehavior.System.ServiceModel.Description.IOperationBehavior.ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
   at System.ServiceModel.Description.DispatcherBuilder.BindOperations(ContractDescription contract, ClientRuntime proxy, DispatchRuntime dispatch)
   at System.ServiceModel.Description.DispatcherBuilder.ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime clientRuntime)
   at System.ServiceModel.Description.DispatcherBuilder.BuildProxyBehavior(ServiceEndpoint serviceEndpoint, BindingParameterCollection& parameters)
   at System.ServiceModel.Channels.ServiceChannelFactory.BuildChannelFactory(ServiceEndpoint serviceEndpoint)
   at System.ServiceModel.ChannelFactory.CreateFactory()
   at System.ServiceModel.ChannelFactory.OnOpening()
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.ChannelFactory.EnsureOpened()
   at System.ServiceModel.ChannelFactory`1.CreateChannel(EndpointAddress address, Uri via)
   at System.ServiceModel.ChannelFactory`1.CreateChannel()
   at System.ServiceModel.ClientBase`1.CreateChannel()
   at System.ServiceModel.ClientBase`1.CreateChannelInternal()
   at System.ServiceModel.ClientBase`1.get_Channel()
   at MissileDefenseSystem.MissileDefenseSystemServiceReference.TestPortTypeClient.MissileDefenseSystem.MissileDefenseSystemServiceReference.TestPortType.LaunchMissiles(LaunchMissilesRequest request) in C:\Users\bra\Documents\Visual Studio 2008\Projects\MissileDefenseSystem\MissileDefenseSystem\Service References\MissileDefenseSystemServiceReference\Reference.cs:line 90
   at MissileDefenseSystem.MissileDefenseSystemServiceReference.TestPortTypeClient.LaunchMissiles(String arg0) in C:\Users\bra\Documents\Visual Studio 2008\Projects\MissileDefenseSystem\MissileDefenseSystem\Service References\MissileDefenseSystemServiceReference\Reference.cs:line 96
   at MissileDefenseSystem.Program.Main(String[] args) in C:\Users\bra\Documents\Visual Studio 2008\Projects\MissileDefenseSystem\MissileDefenseSystem\Program.cs:line 22

сгенерированный код прокси с помощью Visual Studio 2008 (SvcUtil.exe).

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.3074
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------



[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="java:bla.bla.bla.bla", ConfigurationName="TestPortType")]
public interface TestPortType
{

    // CODEGEN: Generating message contract since the wrapper namespace (urn:Test) of message LaunchMissilesRequest does not match the default value (java:bla.bla.bla.bla)
    [System.ServiceModel.OperationContractAttribute(Action="urn:LaunchMissiles", ReplyAction="*")]
    [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)]
    LaunchMissilesResponse LaunchMissiles(LaunchMissilesRequest request);

    // CODEGEN: Generating message contract since the wrapper namespace (urn:Test) of message AbortMissionRequest does not match the default value (java:bla.bla.bla.bla)
    [System.ServiceModel.OperationContractAttribute(Action="urn:AbortMission", ReplyAction="*")]
    [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)]
    LaunchMissilesResponse AbortMission(LaunchMissilesRequest request);
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="LaunchMissiles", WrapperNamespace="urn:Test", IsWrapped=true)]
public partial class LaunchMissilesRequest
{

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=0)]
    public string arg0;

    public LaunchMissilesRequest()
    {
    }

    public LaunchMissilesRequest(string arg0)
    {
        this.arg0 = arg0;
    }
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="LaunchMissilesResponse", WrapperNamespace="urn:Test", IsWrapped=true)]
public partial class LaunchMissilesResponse
{

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=0)]
    public string @return;

    public LaunchMissilesResponse()
    {
    }

    public LaunchMissilesResponse(string @return)
    {
        this.@return = @return;
    }
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface TestPortTypeChannel : TestPortType, System.ServiceModel.IClientChannel
{
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class TestPortTypeClient : System.ServiceModel.ClientBase<TestPortType>, TestPortType
{

    public TestPortTypeClient()
    {
    }

    public TestPortTypeClient(string endpointConfigurationName) : 
            base(endpointConfigurationName)
    {
    }

    public TestPortTypeClient(string endpointConfigurationName, string remoteAddress) : 
            base(endpointConfigurationName, remoteAddress)
    {
    }

    public TestPortTypeClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(endpointConfigurationName, remoteAddress)
    {
    }

    public TestPortTypeClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(binding, remoteAddress)
    {
    }

    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
    LaunchMissilesResponse TestPortType.LaunchMissiles(LaunchMissilesRequest request)
    {
        return base.Channel.LaunchMissiles(request);
    }

    public string LaunchMissiles(string arg0)
    {
        LaunchMissilesRequest inValue = new LaunchMissilesRequest();
        inValue.arg0 = arg0;
        LaunchMissilesResponse retVal = ((TestPortType)(this)).LaunchMissiles(inValue);
        return retVal.@return;
    }

    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
    LaunchMissilesResponse TestPortType.AbortMission(LaunchMissilesRequest request)
    {
        return base.Channel.AbortMission(request);
    }

    public string AbortMission(string arg0)
    {
        LaunchMissilesRequest inValue = new LaunchMissilesRequest();
        inValue.arg0 = arg0;
        LaunchMissilesResponse retVal = ((TestPortType)(this)).AbortMission(inValue);
        return retVal.@return;
    }
}

Это использует прокси-код, созданный SvcUtil.exe.

Загрузите полные файлы проекта Visual Studio здесь:

http://dl.getdropbox.com/u/797094/MissileDefenseSystem.zip

Теперь я просто снова попытался использовать WSDL.exe. Это работает лучше, но теперь следующая проблема поднимает свою уродливую голову. App.config для WCF не используется. Поэтому мне нужно настроить прокси-класс для использования сертификата. Для WCF я просто говорю

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
              <binding name="TestBinding"/>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://demo.blablablablablabla.com:123/Bla"
                binding="basicHttpBinding" bindingConfiguration="TestBinding"
                contract="MissileDefenseSystemServiceReference.TestPortType"
                name="TestPort">
                <identity>
                    <certificateReference storeLocation="CurrentUser" x509FindType="FindByThumbprint"
                        findValue="the thumbprint to be used" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

Хорошо, теперь мы используем фрагмент кода для предоставления подписей

    proxy.ClientCertificates.Add(cert);

Теперь это почти работает, за исключением того, что он не может декодировать ответ.


person Bent Rasmussen    schedule 21.03.2009    source источник
comment
повторное разъяснение по поводу запроса / ответа - см. мое обновление о том, что генерирует wsdl.exe; кажется гораздо более разумным. Краткая версия: используйте для этого wsdl.exe!   -  person Marc Gravell    schedule 22.03.2009
comment
Кстати, я не знал, что java: было допустимым пространством имен XML. Кто-нибудь зарегистрировал это, и если да, то какой URL для этого формата?   -  person John Saunders    schedule 22.03.2009
comment
Это должен быть действительный абсолютный URI, который является единственным требованием для любого пространства имен XML. Схема URI проприетарна, но это не имеет значения. Не знаю о возможных регистрациях.   -  person Bent Rasmussen    schedule 22.03.2009


Ответы (1)


Это зависит от того, что вы ожидаете получить. Это отражено в том, как вы определяете файл wsdl. Например, если вы замените все «urn: Test» на java: bla.bla.bla.bla, вы получите более простое определение, которое просто принимает / возвращает строки.

Если вы все еще хотите получить 2 разных типа запроса / ответа, вы можете использовать это определение:

<?xml version="1.0" encoding="ISO-8859-1"?>
<definitions targetNamespace="java:bla.bla.bla.bla"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:tns="java:bla.bla.bla.bla"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <types>
    <schema targetNamespace='java:bla.bla.bla.bla' xmlns='http://www.w3.org/2001/XMLSchema'/>
  </types>
  <message name="AbortTestRequest">
    <part name="arg0" type="xsd:string"/>
  </message>
  <message name="AbortTestResponse">
    <part name="return" type="xsd:string"/>
  </message>
  <message name="LaunchTestRequest">
    <part name="arg0" type="xsd:string"/>
  </message>
  <message name="LaunchTestResponse">
    <part name="return" type="xsd:string"/>
  </message>
  <portType name="TestPortType">
    <operation name="LaunchMissiles">
      <input message="tns:LaunchTestRequest"/>
      <output message="tns:LaunchTestResponse"/>
    </operation>
    <operation name="AbortMission">
      <input message="tns:AbortTestRequest"/>
      <output message="tns:AbortTestResponse"/>
    </operation>
  </portType>
  <binding name="TestBinding" type="tns:TestPortType">
    <soap:binding style="rpc"  transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="LaunchMissiles">
      <soap:operation soapAction="urn:LaunchMissiles"/>
      <input>
        <soap:body use="encoded" namespace='java:bla.bla.bla.bla/launch' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </input>
      <output>
        <soap:body use="encoded" namespace='java:bla.bla.bla.bla/launch' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </output>
    </operation>
    <operation name="AbortMission">
      <soap:operation soapAction="urn:AbortMission"/>
      <input>
        <soap:body use="encoded" namespace='java:bla.bla.bla.bla/launch' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </input>
      <output>
        <soap:body use="encoded" namespace='java:bla.bla.bla.bla/launch' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
      </output>
    </operation>
  </binding>
  <service name="Test">
    <documentation>todo</documentation>
    <port name="TestPort" binding="tns:TestBinding">
      <soap:address location="https://demo.blablablablablabla.com:123/Bla"/>
    </port>
  </service>
</definitions>

Пс. поскольку вам, кажется, нужны документы запроса / ответа для всех операций / методов, вы можете полностью переключиться на стиль документа.


О невозможности внесения критических изменений в комментарии. Изменение пространств имен или имен элементов сообщения нарушает изменения.

Тем не менее, если вы заинтересованы только в том, чтобы это работало (и не заботитесь о форме классов, которые вы получаете), вы можете использовать ту версию, которая у вас есть. Не имеет значения, что сгенерированные классы используют LaunchMissileResponse для обоих методов, поскольку базовый XML будет одинаковым (TestResponse). Также для вызывающего кода помните, что у вас есть версия, которая получает / отправляет простые строки:

public string AbortMission(string arg0)
person eglasius    schedule 21.03.2009
comment
Все ваши комментарии к моему сообщению (теперь невидимы; я удаляю свой ответ) были хорошими. +1 - person Marc Gravell; 22.03.2009
comment
Если я правильно помню, на самом деле SOAPUI может создавать правильные тестовые запросы из WSDL, который я опубликовал, глядя на XML, который он создает, но это инструмент Java. Любые инструменты .Net, которые я пробую, похоже, не могут его сократить. - person Bent Rasmussen; 22.03.2009
comment
Марк, я могу внести любые неразрывные изменения в WSDL, какие захочу, но я не контролирую определение, мне просто нужно взаимодействовать с этой службой. Но я протестирую это сегодня позже и доложу. Спасибо за вашу помощь. - person Bent Rasmussen; 22.03.2009
comment
@Bent, пожалуйста, проверьте обновление, которое я добавил в конце, если у вас возникли проблемы с его запуском, опубликуйте код, который вы используете для его вызова, и любые подробности об ошибке. - person eglasius; 22.03.2009
comment
Спасибо, Фредди, скоро сделаю! - person Bent Rasmussen; 22.03.2009
comment
См. Мой новый ответ, в котором я разбираю проблему с помощью трассировки исключения. При необходимости я могу отредактировать код прокси, я просто очень разочарован, если мне придется пойти на такую ​​длину. По сути, это означает, что инструмент не работает в этом сценарии. - person Bent Rasmussen; 22.03.2009