Sch*_*ibb 3 c# wcf xsd web-services messagecontract
我收到了一位客户关于其 Web 服务客户端如何工作的规范。该规范是从服务发送和接收的实际 SOAP XML 消息以及相应的 XSD。客户希望我实现一个符合客户要求的网络服务。客户端是用 axis2 ws-stack 编写的,我想做的是在 WCF 中创建一个 Web 服务,它将接受客户端发出的请求并返回符合他们期望的 XML 的响应。在这个问题中,我将只发布与请求相关的 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>
Run Code Online (Sandbox Code Playgroud)
相应的 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>
Run Code Online (Sandbox Code Playgroud)
我已经开始以 WCF/MessageContract 格式编写类型,但我在处理列表等方面遇到了困难,因为它们是双重包装的。
我的消息合同如下所示:
[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;
}
Run Code Online (Sandbox Code Playgroud)
当我使用 SoapUI 时,我从网络服务收到以下响应:
<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>
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它不符合客户端期望的 XML 格式。如何使 MessageContract 符合客户端期望的 XML?我以某种方式需要使列表不像它们那样双重换行,并且类的属性似乎被添加到类名中。
如果您希望我提供更多信息和代码,我可以这样做。不想用可能与问题无关的内容来填充整个帖子。
编辑:
提供的 XSD 文件格式不正确。为了解决这个问题,我从提供的 XML 文件重新生成了 XSD。然后,我使用 WSCF.blue 工具为 XSD 生成数据契约代码。
我进行了更改,以便服务合同使用 doc litteral 格式以符合 axis2soap1.1
[XmlSerializerFormat(Use = OperationFormatUse.Literal, Style = OperationFormatStyle.Document, SupportFaults = true)]
[ServiceContract]
public interface MyService
Run Code Online (Sandbox Code Playgroud)
我还更改了操作契约,将 System.ServiceModel.Channels.Message 作为输入和输出消息,然后使用生成的类(我从 XSD 生成)手动序列化和反序列化 xml。
您最初尝试的问题是您尝试使用[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();
}
}
Run Code Online (Sandbox Code Playgroud)