How can I add a prefix to a WCF ServiceContract Namespace

孤人 提交于 2019-12-04 13:03:21

The two requests which you showed (one by the UPnP control point and one by the WCF Test Client) are not equivalent. The namespace of the children of the Browse element in the first (UPnP) is the empty ("") namespace, while in the second request (WCF TC) it's "urn:schemas-upnp-org:service:ContentDirectory:1" - the empty prefix is bound to the empty namespace unless it's bound to another namespace, and it's rebound in the WCF request but not on the UPnP one.

Now, if you want the namespace of the parameters of an operation to be different than the namespace of the operation itself, you'll have to use a message contract - that'll get the request sent by WCF to be equivalent (modulo prefixes) to the request sent by the UPnP control point. The code below shows how a message contract would be defined to generate a request equivalent to the one you showed for the control point.

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

Now, the request that is sent by WCF is XML-equivalent, but the prefixes are still different. It As John Saunders mentioned, it shouldn't matter, so there's no simple knob in WCF to let you set the prefix for the elements written in the WCF messages. You can, however, use a custom encoder to do exactly that. I posted about it a while back at http://blogs.msdn.com/b/carlosfigueira/archive/2010/06/13/changing-prefixes-in-xml-responses.aspx - you can use that example to create a custom encoder which will set the prefixes to what you expect them to be.

Why do you need a specific prefix? Are you using some software that depends on the prefix?

If that's so, then the software is broken. The two "xmlns" examples you've given are identical as far as XML is concerned. Any software that cares about the difference is badly broken and needs to learn XML.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!