Как добавить префикс в пространство имен WCF ServiceContract - PullRequest
3 голосов
/ 22 марта 2010

Я пытаюсь реализовать UPnP MediaServer в WCF. Я медленно добираюсь туда, но теперь я ударился о кирпичную стену. Мне нужно добавить префикс в пространство имен 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?

UPDATE Вот некоторая дополнительная информация: Следующее сообщение отправлено реальной контрольной точкой 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>

Ответы [ 2 ]

4 голосов
/ 28 июня 2011

Два запроса, которые вы показали (один для контрольной точки UPnP и один для тестового клиента WCF) не эквивалентны . Пространство имен дочерних элементов элемента Browse в первом (UPnP) является пустым ("") пространством имен, тогда как во втором запросе (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, но префиксы все еще разные. Это, как отметил Джон Сондерс, это не должно иметь значения, поэтому в WCF нет простой ручки, позволяющей установить префикс для элементов, записанных в сообщениях WCF. Вы можете, однако, использовать пользовательский кодировщик, чтобы сделать именно это. Некоторое время назад я писал об этом на http://blogs.msdn.com/b/carlosfigueira/archive/2010/06/13/changing-prefixes-in-xml-responses.aspx - вы можете использовать этот пример для создания пользовательского кодировщика, который установит префиксы в ожидаемые значения.

2 голосов
/ 22 марта 2010

Зачем вам нужен определенный префикс?Используете ли вы какое-либо программное обеспечение, которое зависит от префикса?

Если это так, то программное обеспечение не работает.Два приведенных вами примера «xmlns» идентичны с точки зрения XML.Любое программное обеспечение, которое заботится о разнице, сильно сломано и нуждается в изучении XML.

...