我有一系列看起来像这样的对象:
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使用和反序列化了。
有更简单的方法吗?还有更好的方法吗?
答案 0 :(得分:1)
您可以使用调度程序,但是一旦使用了消息,就需要在从方法返回之前重新创建它。下面的代码显示了它的一个例子。
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();
}
}
答案 1 :(得分:0)
这是一个可怕的想法。您正在将XML视为标准并不重要。
MyClass1
命名空间中的元素"http://schemas.datacontract.org/2004/07/MyNamespace"
与默认命名空间中的元素MyClass
不同。
答案 2 :(得分:0)
您还可以使用WcfRestContrib注入支持此行为的自定义XmlSerializer。使用始终完全省略名称空间的XmlSerializer的示例是here。您需要了解如何更新XmlSerializer以选择性地支持名称空间以进行反序列化。
答案 3 :(得分:0)
如果将Servicespace的Namespace设置为Empty,则无需传递xmlns。但是你需要与方法名称匹配的根xml标签,即
<GetItem>
<MyClass1>
<MyProperty>1</MyProperty>
</MyClass1>
</GetItem>