控制 WCF 响应格式和命名空间

5
我希望我的WCF响应使用DataContracts拥有一个包含两个命名空间的响应元素,但我无法让它起作用。这是我想要的响应内容:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <s:Header />
  <s:Body>
    <ns2:TestReply xmlns="http://www.test.org/test/2007/00" xmlns:ns2="http://www.test2.org/test2/types">
      <ns2:Result>
        <ns2:ActionSuccessful>true</ns2:ActionSuccessful>
      </ns2:Result>
      <ns2:ResultData>
        <ns2:Name>Maikel Willemse</ns2:Name>
      </ns2:ResultData>
    </ns2:TestReply>
  </s:Body>
</s:Envelope>

这是我在使用WCF测试客户端进行测试时得到的响应:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header />
  <s:Body>
    <GetDataResponse xmlns="http://www.test.org/test/2007/00">
      <TestReply xmlns:a="http://www.test2.org/test2/types" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <a:Result>
          <a:ActionSuccessful>true</a:ActionSuccessful>
        </a:Result>
        <a:ResultData>
          <a:Name>Maikel Willemse</a:Name>
        </a:ResultData>
      </TestReply>
    </GetDataResponse>
  </s:Body>
</s:Envelope>

我的服务接口看起来像这样:

[ServiceContract(Namespace = "http://www.test.org/test/2007/00")]
public interface IService1
{
    [OperationContract]
    [return: MessageParameter(Name = "TestReply")]
    GetDataResponse GetData(string name);
}

服务类:
public class Service1 : IService1
{
    public GetDataResponse GetData(string name)
    {
        return new GetDataResponse
            {
                Result = new Result {ActionSuccessful = true},
                ResultData = new ResultData {Name = name}
            };
    }
}

数据契约类如下:

[DataContract(Namespace = "http://www.test2.org/test2/types")]
public class GetDataResponse
{
    [DataMember(Name = "Result")]
    public Result Result { get; set; }

    [DataMember(Name = "ResultData")]
    public ResultData ResultData { get; set; }
}

[DataContract(Namespace = "http://www.test2.org/test2/types")]
public class Result
{
    [DataMember(Name = "ActionSuccessful")]
    public bool ActionSuccessful { get; set; }
}

[DataContract(Namespace = "http://www.test2.org/test2/types")]
public class ResultData
{
    [DataMember(Name = "Name")]
    public string Name { get; set; }
}

我的WCF项目目标框架是.NET 4。命名空间前缀不必相同。如何以所需格式获取响应?

2个回答

5

如果您想从响应中删除“包装”元素,则需要使用[MessageContract]。下面的代码显示了一种方法可以完成此操作。并且您可以根据自己的需要调整服务/消息/数据契约中的命名空间。

public class StackOverflow_15173138
{
    [ServiceContract(Namespace = "http://www.test.org/test/2007/00")]
    public interface IService1
    {
        [OperationContract]
        MyResponse GetData(MyRequest request);
    }

    public class Service1 : IService1
    {
        public MyResponse GetData(MyRequest request)
        {
            return new MyResponse
            {
                TestReply = new GetDataResponse
                {
                    Result = new Result { ActionSuccessful = true },
                    ResultData = new ResultData { Name = request.name }
                }
            };
        }
    }

    [MessageContract(IsWrapped = false)]
    public class MyResponse
    {
        [MessageBodyMember]
        public GetDataResponse TestReply { get; set; }
    }

    [MessageContract(WrapperName = "GetData")]
    public class MyRequest
    {
        [MessageBodyMember]
        public string name { get; set; }
    }

    [DataContract(Namespace = "http://www.test2.org/test2/types")]
    public class GetDataResponse
    {
        [DataMember(Name = "Result")]
        public Result Result { get; set; }

        [DataMember(Name = "ResultData")]
        public ResultData ResultData { get; set; }
    }

    [DataContract(Namespace = "http://www.test2.org/test2/types")]
    public class Result
    {
        [DataMember(Name = "ActionSuccessful")]
        public bool ActionSuccessful { get; set; }
    }

    [DataContract(Namespace = "http://www.test2.org/test2/types")]
    public class ResultData
    {
        [DataMember(Name = "Name")]
        public string Name { get; set; }
    }

    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service1), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(IService1), new BasicHttpBinding(), "");
        host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
        host.Open();
        Console.WriteLine("Host opened");

        ChannelFactory<IService1> factory = new ChannelFactory<IService1>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
        IService1 proxy = factory.CreateChannel();
        Console.WriteLine(proxy.GetData(new MyRequest { name = "hello" }));

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

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}

谢谢您的快速回答,这几乎是我想要的。XML的布局正是我想要的,但<TestReply>元素没有"a:"前缀...有什么想法吗? - Maikel Willemse
没有简单的方法来自定义 WCF 生成的 XML 中的前缀 - 前缀应该仅用于定义命名空间,通常您无法选择使用哪个前缀。如果您真的想要自定义它们,可以这样做,但这并不容易 - http://blogs.msdn.com/b/carlosfigueira/archive/2010/06/13/changing-prefixes-in-xml-responses.aspx 上的文章展示了一种方法。 - carlosfigueira
对不起,那不是我的意思。我不介意前缀为“a”,但我希望<TestReply>节点(因此是body的第一个子节点)也有它:<a:TestReply ...>。使用您的代码时,<TestReply>内部的所有节点都具有前缀(这很好),但<TestReply>节点本身没有。 - Maikel Willemse

1

给@Maikel TestReply在默认命名空间中,因此没有前缀,但其中的元素确实有。

xmlns:a="http://www.test2.org/test2/types

因为'a=',所以此命名空间的前缀为a,与默认命名空间不同。

在您的方法的ServiceContractAttribute中

GetDataResponse GetData(string name); 

如@Carlos建议,您可以编写

as @Carlos suggested, you can write


[ServiceContract(Namespace="http://www.test2.org/test2/types")]

你不能拥有这个

<a:TestReply xmnls:a="http://www.test2.org/test2/types">

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接