Как я могу поддерживать XML с или без пространства имен, с моей службой WCF HTTP REST - PullRequest
3 голосов
/ 22 сентября 2011

У меня есть ряд объектов, которые выглядят так:

namespace MyNamespace
{
  [DataContract(Namespace="")]
  public class MyClass1
  {
    [DataMember]
    public string MyProperty {get;set;}
  }
}

У меня есть метод, который выставляет WebInvoke, который выглядит следующим образом (очень упрощенный, поскольку сейчас он фактически ничего не делает, но все еще работает для этого теста)

[WebInvoke(UriTemplate = "", Method="POST")]
public MyNamespace.MyClass1 GetItem(MyClass1 postedItem) { return postedItem; }

Мне бы очень хотелось иметь возможность принимать XML, который выглядит следующим образом:

<MyClass1>
  <MyProperty>1</MyProperty>
</MyClass1>

или это:

<MyClass1 xmlns:"http://schemas.datacontract.org/2004/07/MyNamespace">
  <MyProperty>1</MyProperty>
</MyClass1>

Но пока что мои исследования показывают, что это невозможно. Моя единственная идея сейчас заключается в том, чтобы использовать IDispatchMessageInspector и использовать сообщение, удалить пространство имен xmlns, а затем разрешить WCF продолжить обработку сообщения. Однако мне не очень повезло с этим, потому что, как только я получу сообщение, он больше не будет доступен для потребления и десериализации WCF.

Есть ли более простой способ? Есть ли лучший способ?

Ответы [ 4 ]

1 голос
/ 22 сентября 2011

Вы можете использовать диспетчер, но как только вы получите сообщение, вам нужно будет воссоздать его, прежде чем вернуться из метода.Код ниже показывает пример этого.

public class StackOverflow_7506072
{
    [DataContract(Name = "MyClass1", Namespace = "")]
    public class MyClass1
    {
        [DataMember]
        public string MyProperty { get; set; }
    }
    [ServiceContract]
    public class Service
    {
        [WebInvoke(UriTemplate = "", Method = "POST")]
        public MyClass1 GetItem(MyClass1 postedItem) { return postedItem; }
    }
    public class MyInspector : IEndpointBehavior, IDispatchMessageInspector
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            MemoryStream ms = new MemoryStream();
            XmlWriter w = XmlWriter.Create(ms);
            request.WriteMessage(w);
            w.Flush();
            ms.Position = 0;
            XElement element = XElement.Load(ms);
            if (element.Name.NamespaceName == "http://schemas.datacontract.org/2004/07/MyNamespace")
            {
                element.Name = XName.Get(element.Name.LocalName, "");
                foreach (XElement child in element.Descendants())
                {
                    if (child.Name.NamespaceName == "http://schemas.datacontract.org/2004/07/MyNamespace")
                    {
                        child.Name = XName.Get(child.Name.LocalName, "");
                    }
                }

                element.Attribute("xmlns").Remove();
            }

            XmlReader r = element.CreateReader();
            Message newRequest = Message.CreateMessage(r, int.MaxValue, request.Version);
            newRequest.Properties.CopyProperties(request.Properties);
            request = newRequest;
            return null;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "");
        endpoint.Behaviors.Add(new WebHttpBehavior());
        endpoint.Behaviors.Add(new MyInspector());
        host.Open();
        Console.WriteLine("Host opened");

        WebClient c = new WebClient();
        c.Headers[HttpRequestHeader.ContentType] = "text/xml";
        string xml = "<MyClass1><MyProperty>123</MyProperty></MyClass1>";
        Console.WriteLine(c.UploadString(baseAddress + "/", xml));

        c = new WebClient();
        c.Headers[HttpRequestHeader.ContentType] = "text/xml";
        xml = "<MyClass1 xmlns=\"http://schemas.datacontract.org/2004/07/MyNamespace\"><MyProperty>123</MyProperty></MyClass1>";
        Console.WriteLine(c.UploadString(baseAddress + "/", xml));

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
0 голосов
/ 12 марта 2014

Если вы установите Пустое пространство имен для службы, вам не нужно передавать xmlns.Но вам нужен корневой тег XML, соответствующий имени метода, т.е.

<GetItem>
<MyClass1>
  <MyProperty>1</MyProperty>
</MyClass1>
</GetItem>
0 голосов
/ 14 февраля 2012

Вы также можете использовать WcfRestContrib для добавления пользовательского XmlSerializer, который поддерживает это поведение. Пример, который использует XmlSerializer, который всегда полностью пропускает пространства имен: здесь . Вам нужно будет решить, как обновить XmlSerializer, чтобы дополнительно поддерживать пространства имен для десериализации.

0 голосов
/ 22 сентября 2011

Это ужасная идея.Вы рассматриваете XML так, как будто стандарт не имеет значения.

Элемент MyClass1 в пространстве имен "http://schemas.datacontract.org/2004/07/MyNamespace" отличается от элемента MyClass в пространстве имен по умолчанию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...