3

顧客から、Webサービスクライアントがどのように機能するかについての仕様を受け取りました。仕様は、サービスおよび対応するXSDとの間で送受信される実際のSOAPXMLメッセージです。顧客は、クライアントに準拠したWebサービスを実装することを望んでいます。クライアントはaxis2ws-stackで記述されており、私がやろうとしているのは、クライアントからの要求を受け入れ、期待しているXMLに準拠した応答を返すWebサービスをWCFで作成することです。この質問では、リクエストに関連付けられたXMLとXSDのみを投稿します。これを機能させることができれば、同様の方法で応答が行われるためです。

私が受け取ったXMLは次のとおりです。

POST /axis2/services/SampleService HTTP/1.1
Content-Type: text/xml; charset=UTF-8
SOAPAction: "sendCommand"
User-Agent: Axis2
Host: 127.0.0.1:7777
Content-Length: 347
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> 
   <soapenv:Body> 
      <SendCommandRequest xmlns="http://something.org/"> 
         <CMD> 
            <Station Address="ABC"> 
               <Platform Address="DEF"> 
                  <Command>5</Command> 
               </Platform> 
             </Station> 
         </CMD> 
       </SendCommandRequest> 
    </soapenv:Body>
</soapenv:Envelope>

対応するXSDは次のようになります。

<xsd:complexType name="SendCommandRequestType"> 
    <xsd:sequence>  
        <xsd:element name="Station"> 
            <xsd:complexType> 
                <xsd:attribute name="Address" type="xsd:string" use="required" /> 
                <xsd:sequence> 
                    <xsd:element minOccurs="0" maxOccurs="1" name="Platform"> 
                        <xsd:complexType> 
                            <xsd:attribute name="Address" type="xsd:string" use="required" /> 
                            <xsd:sequence> 
                                <xsd:element name="Command"> 
                                    <xsd:simpleType> 
                                        <xsd:restriction base="xsd:string"> 
                                            <xsd:enumeration value="-1"/> 
                                            <xsd:enumeration value="0"/> 
                                            <xsd:enumeration value="1"/> 
                                            <xsd:enumeration value="2"/> 
                                            <xsd:enumeration value="3"/> 
                                            <xsd:enumeration value="4"/> 
                                            <xsd:enumeration value="5"/> 
                                        </xsd:restriction> 
                                    </xsd:simpleType> 
                                </xsd:element> 
                            </xsd:sequence> 
                        </xsd:complexType> 
                    </xsd:element> 
                </xsd:sequence> 
            <xsd:complexType>
        </xsd:element>
    </xsd:sequence>
</xsd:complexType>

タイプをWCF/MessageContract形式で記述し始めましたが、リストなどが二重にラップされているため、苦労しています。

私のMessageContractsは次のようになります。

[MessageContract(WrapperName = "SendCommandRequest", WrapperNamespace = "http://something.org/")]
public class SendCommandRequest
{
    [MessageBodyMember(Name="CMD")]
    public CMD cmd = new CMD();
}

[MessageContract(IsWrapped=false)]
public class CMD
{
    [MessageBodyMember(Name="Station")]
    public List<Station> stations = new List<Station>();
}

[MessageContract(IsWrapped=false)]
public class Station
{

    [MessageBodyMember]
    public List<Platform> platforms = new List<Platform>();
    [MessageBodyMember(Name="Address")]
    public String Address; 
}

[MessageContract(WrapperName = "Platform")]
public class Platform
{
    [MessageBodyMember(Name = "Address")]
    public String Address;
}

SoapUIを使用してWebサービスから次の応答を取得すると、次のようになります。

 <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
   <s:Body>
      <SendCommandRequest xmlns="http://ttraflinariawebservice.org/">
         <CMD xmlns="http://tempuri.org/" xmlns:a="http://schemas.datacontract.org/2004/07/GeldImport" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <a:stations>
               <a:Station>
                  <a:Address>test</a:Address>
                  <a:platforms>
                     <a:Platform>
                        <a:Address>b</a:Address>
                     </a:Platform>
                  </a:platforms>
               </a:Station>
            </a:stations>
         </CMD>
      </SendCommandRequest>
   </s:Body>
</s:Envelope>

ご覧のとおり、クライアントが期待するXML形式に適合していません。MessageContractをクライアントが期待するXMLに準拠させるにはどうすればよいですか?どういうわけか、リストをダブルラップしないようにする必要があり、クラスのプロパティがクラス名に追加されているようです。

より多くの情報とコードを提供してほしい場合は、そうすることができます。質問に関係がないかもしれないもので投稿全体を埋めたくありませんでした。

編集:

提供されたXSDファイルは適切にフォーマットされていませんでした。これを解決するために、提供されたXMLファイルからXSDを再生成しました。次に、WSCF.blueツールを使用して、XSDのデータコントラクトコードを生成しました。

私は、サービス契約がaxis2soap1.1に準拠するためにドキュメント文字フォーマットを使用するように変更しました

[XmlSerializerFormat(Use = OperationFormatUse.Literal, Style = OperationFormatStyle.Document, SupportFaults = true)]
[ServiceContract]
public interface MyService

また、操作コントラクトを変更して、入力メッセージと出力メッセージとしてSystem.ServiceModel.Channels.Messageを使用し、生成されたクラス(XSDから生成)を使用してxmlを手動でシリアル化および逆シリアル化しました。

4

1 に答える 1

4

最初の試みの問題は、クラスを使用してメッセージのデータコントラクト (スキーマ)[MessageContract]を定義しようとしていることです。メッセージ コントラクトは、最上位のクラスとしてのみ使用されます (メッセージ ヘッダーに入れるものと本文に入れるものを定義するため)。他のクラスは、使用しているシリアライザーの属性を使用する必要があります (また、XML 属性があるため、XmlSerializer を使用する必要があります)。以下のコードは、指定したスキーマに準拠したオブジェクト モデルを取得する方法を示しています。Fiddler などのツールを使用して、送信された要求を確認できます。

public class StackOverflow_13739729
{
    [ServiceContract(Namespace = "http://something.org")]
    public interface ITest
    {
        [XmlSerializerFormat, OperationContract(Name = "sendCommand")]
        void SendCommand(SendCommandRequest req);
    }

    public class Service : ITest
    {
        public void SendCommand(SendCommandRequest req)
        {
            Console.WriteLine("In service");
        }
    }

    [MessageContract(WrapperName = "SendCommandRequest", WrapperNamespace = "http://something.org")]
    public class SendCommandRequest
    {
        [MessageBodyMember]
        public CMD CMD { get; set; }
    }

    [XmlType]
    public class CMD
    {
        [XmlElement]
        public Station Station { get; set; }
    }

    public class Station
    {
        [XmlAttribute]
        public string Address { get; set; }

        [XmlElement]
        public Platform Platform { get; set; }
    }

    public class Platform
    {
        string[] validCommands = new[] { "-1", "0", "1", "2", "3", "4", "5" };
        string[] command;

        [XmlAttribute]
        public string Address { get; set; }

        [XmlElement]
        public string[] Command
        {
            get { return this.command; }
            set
            {
                if (value != null)
                {
                    if (!value.All(c => validCommands.Contains(c)))
                    {
                        throw new ArgumentException("Invalid command");
                    }
                }

                this.command = value;
            }
        }
    }

    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
        host.Open();
        Console.WriteLine("Host opened");

        ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
        ITest proxy = factory.CreateChannel();

        SendCommandRequest req = new SendCommandRequest
        {
            CMD = new CMD
            {
                Station = new Station
                {
                    Address = "ABC",
                    Platform = new Platform
                    {
                        Address = "DEF",
                        Command = new string[] { "5" }
                    }
                }
            }
        };

        proxy.SendCommand(req);

        ((IClientChannel)proxy).Close();
        factory.Close();

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
于 2012-12-06T18:32:41.530 に答える