MessageContract包装和列表

MessageContract包装和列表

本文介绍了WCF MessageContract包装和列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从客户那里收到了有关其Web服务客户端工作方式的规范.该规范是从服务以及相应的XSD发送和接收的实际SOAP XML消息.客户希望我实施符合客户要求的Web服务.客户端是用axis2 ws-stack编写的,而我想做的是在WCF中创建一个Web服务,该服务将接受客户端提出的请求并返回符合他们期望的XML的响应.在这个问题中,我将仅发布与请求关联的XML和XSD,因为如果可以使它正常工作,则响应将以类似的方式进行.

I've received a specification from a customer of how their web-service client works. The specification is the actual SOAP XML messages that are sent and received from the service as well as the corresponding XSD. The customer want me to implement a web-service that comply with the client. The client is written with axis2 ws-stack and what i'm trying to do is to create a web-service in WCF that will accept the requests made by the client and return a response that comply with the XML that they are expecting. In this question I will only post the XML and XSD associated with the request, because if I can get that to work, the response will be made in a similar fashion.

我收到的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的样子:

This is what the corresponding XSD looks like:

<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格式编写类型,但是我很难处理列表等内容,因为它们是双重包装的.

I've started to write the types in WCF/MessageContract format, but I'm having a difficult time with lists etc, since they are double wrapped.

我的MessageContracts看起来像这样:

My MessageContracts looks like this:

[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服务获得以下响应:

When I use SoapUI to I get the following response from the web-service:

 <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?我不知何故需要使List不能像它们那样进行双重包装,并且类的属性似乎已添加到类名称中.

As you can see it doesn't fit the XML format that the client expects. How can I get the MessageContract to comply with the XML that the client expects? I somehow need to make Lists not double wrap like they do, and the properties of the classes seems to be added to the class name.

如果您希望我提供更多的信息和代码,我可以提供.不想用可能与问题无关的内容来填补整个帖子.

If you want me to provide more information and code I can do so. Didn't want to fill the whole post with things which might not be relevant to the question.

提供的XSD文件格式不正确.为了解决这个问题,我从提供的XML文件中重新生成了XSD.然后,我使用WSCF.blue工具为XSD生成数据协定代码.

The provided XSD file was not well formatted. In order to solve this i regenerated an XSD from the provided XML file. I then used WSCF.blue tool to generate data contract code for the XSD.

我进行了更改,以便服务合同使用doc文本格式来遵守axis2 soap1.1

I changed so that the service contract used doc litteral formatting to comply with axis2 soap1.1

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

我还更改了操作协定,以将System.ServiceModel.Channels.Message作为输入和输出消息,然后使用生成的类(由XSD生成)手动对XML进行序列化和反序列化.

I also changed the operation contract to have System.ServiceModel.Channels.Message as input and output message and then manually serialized and deserialized the xml using the generated classes (which I generated from the XSD).

推荐答案

最初尝试的问题是您试图使用[MessageContract]类定义 data 合同(模式)消息.消息协定仅用作最高级的类(以定义消息头中包含的内容以及正文中所包含的内容).其他类需要使用所使用的任何序列化程序的属性(并且由于具有XML属性,因此需要使用XmlSerializer).下面的代码显示了如何使对象模型与您提供的模式兼容.您可以使用Fiddler之类的工具查看其发送的请求.

Your prolem with the original attempt is that you're trying to use [MessageContract] classes to define the data contract (schema) of the message. Message contracts are only used as the top-most classes (to define what goes into the message header and what goes into the body). The other classes need to use the attributes for whichever serializer you're using (and since you have XML attributes, you need to use the XmlSerializer). The code below shows how to get an object model compliant with the schema you provided. You can use a tool such as Fiddler to see the request it sends.

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();
    }
}

这篇关于WCF MessageContract包装和列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 20:42