【问题标题】:How can I add a prefix to a WCF ServiceContract Namespace如何向 WCF ServiceContract 命名空间添加前缀
【发布时间】:2010-03-22 19:46:09
【问题描述】:

我正在尝试在 WCF 中实现 UPnP MediaServer。我正在慢慢到达那里,但现在我碰上了一堵砖墙。我需要为 ServiceContract 命名空间添加一个前缀。现在我有以下内容:

[ServiceContract(Namespace = "urn:schemas-upnp-org:service:ContentDirectory:1")]
public interface  IContentDirectory
{
    [OperationContract(Action = "urn:schemas-upnp-org:service:ContentDirectory:1#Browse")]
    void Browse(string ObjectID, string BrowseFlag, string Filter, ulong StartingIndex, ulong RequestedCount, string SortCriteria, out string Result, out ulong NumberReturned, out ulong TotalMatches, out ulong UpdateID);
}

这会监听正确的肥皂信息。但是,我需要肥皂体开始

<u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">

WCF 现在正在收听:

<Browse xmlns="urn:schemas-upnp-org:service:ContentDirectory:1">

我如何在那里获得前缀?有关系吗?或者还有其他原因导致没有将参数传递到 Browse 方法中?

更新 以下是一些额外信息: 以下消息由真正的 UPnP 控制点发送。参数传递到 Browse 方法中。

<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://XXXXX:8731/ContentDirectory</To>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:schemas-upnp-org:service:ContentDirectory:1#Browse</Action>
  </s:Header>
  <s:Body>
      <u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
         <ObjectID>0</ObjectID>
         <BrowseFlag>BrowseDirectChildren</BrowseFlag>
         <Filter>*</Filter>
         <StartingIndex>0</StartingIndex>
         <RequestedCount>15</RequestedCount>
         <SortCriteria />
      </u:Browse>
   </s:Body>
</s:Envelope>

这是由 WCF 测试客户端生成的请求。现在参数被传递到 Browse 方法中:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://XXXXXX:8731/ContentDirectory</To>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:schemas-upnp-org:service:ContentDirectory:1#Browse</Action>
  </s:Header>
  <s:Body>
    <Browse xmlns="urn:schemas-upnp-org:service:ContentDirectory:1">
      <ObjectID>0</ObjectID>
      <BrowseFlag>BrowseMetadata</BrowseFlag>
      <Filter>*</Filter>
      <StartingIndex>0</StartingIndex>
      <RequestedCount>0</RequestedCount>
      <SortCriteria i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
    </Browse>
  </s:Body>
</s:Envelope>

【问题讨论】:

  • 请显示更多导致问题的 XML。前缀不是问题。 WCF 正确实现 XML,因此不关心前缀。
  • 您是否有幸找到了此问题的答案?我也在为同样的事情苦苦挣扎。

标签: c# .net wcf upnp


【解决方案1】:

您显示的两个请求(一个来自 UPnP 控制点,一个来自 WCF 测试客户端)不等效。第一个 (UPnP) 中 Browse 元素的子元素的命名空间是空的 ("") 命名空间,而在第二个请求 (WCF TC) 中它是 "urn:schemas-upnp-org:service:ContentDirectory:1" -空前缀绑定到空命名空间,除非它绑定到另一个命名空间,并且它会在 WCF 请求中反弹,但不会在 UPnP 请求中反弹。

现在,如果您希望操作参数的命名空间与操作本身的命名空间不同,则必须使用消息协定 - 这将使 WCF 发送的请求等效(模前缀)到 UPnP 控制点发送的请求。下面的代码显示了如何定义消息协定以生成与您为控制点显示的请求等效的请求。

public class StackOverflow_2495195
{
    [MessageContract(WrapperName="Browse", WrapperNamespace="urn:schemas-upnp-org:service:ContentDirectory:1", IsWrapped=true)]
    public class BrowseRequest
    {
        [MessageBodyMember(Namespace = "", Order = 0)]
        public string ObjectID;

        [MessageBodyMember(Namespace = "", Order = 1)]
        public string BrowseFlag;

        [MessageBodyMember(Namespace = "", Order = 2)]
        public string Filter;

        [MessageBodyMember(Namespace = "", Order = 3)]
        public ulong StartingIndex;

        [MessageBodyMember(Namespace = "", Order = 4)]
        public ulong RequestedCount;

        [MessageBodyMember(Namespace = "", Order = 5)]
        public string SortCriteria;
    }

    [MessageContract(WrapperName = "BrowseResponse", WrapperNamespace = "urn:schemas-upnp-org:service:ContentDirectory:1", IsWrapped = true)]
    public class BrowseResponse
    {
        [MessageBodyMember(Namespace = "", Order = 0)]
        public string Result;

        [MessageBodyMember(Namespace = "", Order = 1)]
        public ulong NumberReturned;

        [MessageBodyMember(Namespace = "", Order = 2)]
        public ulong TotalMatches;

        [MessageBodyMember(Namespace = "", Order = 3)]
        public ulong UpdateID;
    }

    [ServiceContract(Namespace = "urn:schemas-upnp-org:service:ContentDirectory:1")]
    public interface IContentDirectory
    {
        [OperationContract(Action = "urn:schemas-upnp-org:service:ContentDirectory:1#Browse")]
        //void Browse(string ObjectID, string BrowseFlag, string Filter, ulong StartingIndex, ulong RequestedCount, string SortCriteria, out string Result, out ulong NumberReturned, out ulong TotalMatches, out ulong UpdateID);
        BrowseResponse Browse(BrowseRequest request);
    }
    public class Service : IContentDirectory
    {
        //public void Browse(string ObjectID, string BrowseFlag, string Filter, ulong StartingIndex, ulong RequestedCount, string SortCriteria, out string Result, out ulong NumberReturned, out ulong TotalMatches, out ulong UpdateID)
        //{
        //    Result = null;
        //    NumberReturned = 0;
        //    TotalMatches = 0;
        //    UpdateID = 0;
        //}
        public BrowseResponse Browse(BrowseRequest request)
        {
            return new BrowseResponse { NumberReturned = 0, Result = null, TotalMatches = 0, UpdateID = 0 };
        }
    }
    static Binding GetBinding()
    {
        return new CustomBinding(
            new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressing10, Encoding.UTF8),
            new HttpTransportBindingElement());
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(IContentDirectory), GetBinding(), "");
        host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
        host.Open();
        Console.WriteLine("Host opened");

        ChannelFactory<IContentDirectory> factory = new ChannelFactory<IContentDirectory>(GetBinding(), new EndpointAddress(baseAddress));
        IContentDirectory proxy = factory.CreateChannel();
        //string result;
        //ulong ul1, ul2, ul3;
        //proxy.Browse(null, null, null, 0, 0, null, out result, out ul1, out ul2, out ul3);
        proxy.Browse(new BrowseRequest { BrowseFlag = null, Filter = null, ObjectID = null, RequestedCount = 0, SortCriteria = null, StartingIndex = 0 });

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

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

现在,WCF 发送的请求是 XML 等效的,但前缀仍然不同。正如 John Saunders 所提到的,这无关紧要,因此 WCF 中没有简单的旋钮可以让您为 WCF 消息中写入的元素设置前缀。但是,您可以使用自定义编码器来做到这一点。我不久前在http://blogs.msdn.com/b/carlosfigueira/archive/2010/06/13/changing-prefixes-in-xml-responses.aspx 上发布了它——您可以使用该示例创建一个自定义编码器,它将前缀设置为您期望的前缀。

【讨论】:

  • 哇,这正是我想要的。似乎 UPnP 有一个非常奇怪的 SOAP 信封实现,需要这种设置才能工作。
【解决方案2】:

为什么需要一个特定的前缀?你在使用一些依赖前缀的软件吗?

如果是这样,那么软件就坏了。就 XML 而言,您给出的两个“xmlns”示例是相同的。任何关心差异的软件都严重损坏,需要学习 XML。

【讨论】:

  • 我知道,但这是填充参数的肥皂请求和不填充参数的请求之间的唯一区别。此外,UPnP 规范似乎对该前缀非常明确。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-22
  • 1970-01-01
相关资源
最近更新 更多