从WCF restful响应中删除xml名称空间
我使用WCF将一个普通的旧XML(POX)文档返回给调用者。我正在使用XML序列化器格式化程序将对象转换为XML 在返回的文档中,我有一些与xml模式和实例无关的xml名称空间引用(ASMX版本中没有)。我在网上看到了各种各样的论点,这些论点不应该被删除,我不相信这些论点会返回一个普通的XML文档 从WCF中返回的XML文档中删除这些xmlns引用的最简单方法是什么 签名看起来像:从WCF restful响应中删除xml名称空间,xml,wcf,serialization,namespaces,Xml,Wcf,Serialization,Namespaces,我使用WCF将一个普通的旧XML(POX)文档返回给调用者。我正在使用XML序列化器格式化程序将对象转换为XML 在返回的文档中,我有一些与xml模式和实例无关的xml名称空间引用(ASMX版本中没有)。我在网上看到了各种各样的论点,这些论点不应该被删除,我不相信这些论点会返回一个普通的XML文档 从WCF中返回的XML文档中删除这些xmlns引用的最简单方法是什么 签名看起来像: public ResponseInfo Process(string input) { } 在我的restful
public ResponseInfo Process(string input) {
}
在我的restfulwcf服务中,我在WCF restfulstarter工具包之前编写了以下内容,这给了我很好的、干净的结果 首先,确保设置了webHttp端点行为:
<endpointBehaviors>
<behavior name="Web">
<webHttp/>
</behavior>
</endpointBehaviors>
服务实现本身没有什么特别之处。您可以尝试更改WebMessageFormat,但枚举中唯一的其他项是“json”。我假设您正在尝试,而不是在xml的开头获得类似的内容:
<ResponseInfo
xmlns="http://schemas.datacontract.org/2004/07/ResponseInfo"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance" >
你只需要:
<ResponseInfo>
遗憾的是,我还没有找到一个简单的方法来删除这些字段。我在谷歌上搜索解决方案,删除它的大多数选项都需要创建自己的消息检查器或编码器。您可以通过将DataContract属性的名称空间参数设置为空字符串来删除XML名称空间,如下所示:
[DataContract(Namespace = "")]
public class ResponseInfo
{
// ...
}
我希望这有助于……如果您想更改Xml,其中一种方法是使用XslTransform。我有一个类似的例子,我需要从XMLPOST请求中删除xmlns属性 在WCF中,您可以通过实现IClientMessageInspector或IDispatchMessageInspector,在发出Xml消息之前或在进入过程中处理Xml消息之前“截获”Xml消息,具体取决于您是在客户端还是服务器端需要它 例如,为了将传出Xml消息中的命名空间属性剥离到web服务,我使用以下代码实现了IClientMessageInspector:
#region IClientMessageInspector Members
public void AfterReceiveReply(ref Message reply, object correlationState)
{
//Console.WriteLine(reply.ToString());
}
private XslCompiledTransform xt = null;
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
Console.WriteLine(request.ToString());
if (!request.IsEmpty)
{
XmlReader bodyReader =
request.GetReaderAtBodyContents().ReadSubtree();
MemoryStream ms = new MemoryStream();
XmlWriter xw = XmlWriter.Create(ms);
if (xt == null)
{
xt = new XslCompiledTransform(true);
xt.Load("StripXmlnsi.xslt");
}
xt.Transform(bodyReader, xw);
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
bodyReader = XmlReader.Create(ms);
Message changedMessage = Message.CreateMessage(request.Version, null, bodyReader);
changedMessage.Headers.CopyHeadersFrom(request.Headers);
changedMessage.Properties.CopyProperties(request.Properties);
request = changedMessage;
}
return null;
}
#endregion
并使用以下转换:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="*">
<!-- remove element prefix (if any) -->
<xsl:element name="{local-name()}">
<!-- process attributes -->
<xsl:for-each select="@*">
<!-- remove attribute prefix (if any) -->
<xsl:attribute name="{local-name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
希望这是有帮助的。如果名称空间对于您的项目来说是唯一的,那么请给出另一种观点,例如: 那么它应该被保留 这样的名称空间是最佳实践,它们将为任何XPath调用添加不到1行的样板文件(您可以将其转换为帮助器方法),并且需要大约15行帮助器代码来生成前缀/URI映射,但这是唯一的缺点,您不会总是遇到它 在exchange中,您可以为每个元素获得明确的名称,这意味着您可以免费编写第三方名称空间,例如,理论上,您可以直接返回XHTML,而无需应用程序级编码 出现的其他名称空间不太可能成为问题,因为它们不太可能用于您在项目中定义的任何标记上。事实上,如果它们是,那么某处就有一个bug。对其存在的可能解释是,框架添加了它们,以防需要在声明它们的位置下方的某个位置添加元素,而这可能不是您需要关心的位置 另一个答案提到了有点特别的问题,也许你可以说添加了哪些名称空间。我也有同样的问题。 向WebInvoke添加BodyStyle:=WebMessageBodyStyle.Bare对我来说很有效。
响应不再封装在元数据中。不确定这是否有帮助,但我们遇到了类似的问题。我们发现,如果我们的WCF服务改用XmlSerializerFormat,我们可以轻松地反序列化对象,而不是使用DataContract/DataMember属性装饰数千个数据元素并使用(默认)DataContractSerializer
[System.ServiceModel.ServiceContract]
public interface IRestService
{
[System.ServiceModel.OperationContract]
// Added this attribute to use XmlSerializer instead of DataContractSerializer
[System.ServiceModel.XmlSerializerFormat(
Style=System.ServiceModel.OperationFormatStyle.Document)]
[System.ServiceModel.Web.WebGet(
ResponseFormat = System.ServiceModel.Web.WebMessageFormat.Xml,
UriTemplate = "xml/objects/{myObjectIdentifier}")]
MyObject GetMyObject(int myObjectIdentifier);
}
这就是我们反序列化对象的方式:
public static T DeserializeTypedObjectFromXmlString<T>(string input)
{
T result;
try
{
System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(T));
using (System.IO.TextReader textReader = new System.IO.StringReader(input))
{
result = (T)xs.Deserialize(textReader);
}
}
catch
{
throw;
}
return result;
}
public static T反序列化TypedObjectFromXMLString(字符串输入)
{
T结果;
尝试
{
System.Xml.Serialization.XmlSerializer xs=new System.Xml.Serialization.XmlSerializer(typeof(T));
使用(System.IO.TextReader TextReader=new System.IO.StringReader(输入))
{
结果=(T)xs.反序列化(textReader);
}
}
抓住
{
投掷;
}
返回结果;
}
我找到了一个很好的解决方案,它允许您将自己的XmlSerializer注入WCF,在序列化和反序列化请求时使用WCF。可以将此XmlSerializer设置为完全省略XML名称空间(包括xmlns:i=“w3.org/2001/XMLSchema instance”
)或您希望的任何其他方式
我的解决方案是利用。您几乎可以使用include,但在我们的例子中,我们希望支持属性,所以我们编写了自己的简单格式化程序
说明:
1) 从项目中引用WcfRestContrib
2) 创建IWebFormatter
实现:
public class NamespacelessXmlFormatter : IWebFormatter {
public object Deserialize(WebFormatterDeserializationContext context, Type type) {
if (context.ContentFormat != WebFormatterDeserializationContext.DeserializationFormat.Xml) {
throw new InvalidDataException("Data must be in xml format.");
}
return NamespacelessXmlSerializer.Deserialize(context.XmlReader, type);
}
public WebFormatterSerializationContext Serialize(object data, Type type) {
using (var stream = NamespacelessXmlSerializer.Serialize(data, type)) {
using (var binaryReader = new BinaryReader(stream)) {
byte[] bytes = binaryReader.ReadBytes((int)stream.Length);
return WebFormatterSerializationContext.CreateBinary(bytes);
}
}
}
}
它利用了一个适合您需要的XmlSerializer(这里是我们的,它简单地省略了所有名称空间):
4) 将WebDispatchFormatter
属性应用于所有服务方法(基于此)
5) 就这样。测试您的服务并确认它现在的行为符合预期。当我与ASMX客户端一起工作时,我遇到了相同的问题,对我来说,这可以解决问题: 添加到您的服务界面:
[XmlSerializerFormat(Use = OperationFormatUse.Literal, Style = OperationFormatStyle.Document)]
添加到操作中:
[OperationContract(Action = "http://www.YourNameSpace.com/ActionName",ReplyAction = "http://www.YourNameSpace.com/ActionName")]
这是可行的,但您可能需要在字段上放置[DataMember]属性,以确保xml不会从我的测试中为空。此方法不会删除xmlns:i=”“声明如果downvoter会留下注释,那就太好了。我的答案是100%正确和可行的。它可能不完全符合提问者的需求,或者可能有更好的方法,但它确实有效。我不是反对者,但尽管你的答案可能是“正确的”,但它并没有回答这个特定的问题
public static class NamespacelessXmlSerializer {
private static readonly XmlSerializerNamespaces _customNamespace = new XmlSerializerNamespaces();
private static readonly XmlWriterSettings _xmlSettings = new XmlWriterSettings {
OmitXmlDeclaration = true
};
static NamespacelessXmlSerializer() {
// to make sure .NET serializer doesn't add namespaces
_customNamespace.Add(String.Empty, String.Empty);
}
/// <summary>
/// Deserializes object from its XML representation.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="stream"></param>
/// <returns></returns>
public static T Deserialize<T>(Stream stream) {
return (T)Deserialize(stream, typeof(T));
}
/// <summary>
/// Deserializes object from its XML representation.
/// </summary>
public static object Deserialize(Stream stream, Type type) {
var ds = new XmlSerializer(type);
var d = ds.Deserialize(stream);
return d;
}
public static object Deserialize(XmlDictionaryReader xmlReader, Type type) {
var ds = new XmlSerializer(type);
var d = ds.Deserialize(xmlReader);
return d;
}
/// <summary>
/// Serializes object to XML representation.
/// </summary>
/// <exception cref="InvalidOperationException">
/// Is thrown when there was an error generating XML document. This can happen
/// for example if the object has string with invalid XML characters:
/// http://www.w3.org/TR/2004/REC-xml-20040204/#charsets.
/// See this article for other potential issues:
/// http://msdn.microsoft.com/en-us/library/aa302290.aspx
/// </exception>
public static Stream Serialize<T>(T objectToSerialize) {
return Serialize(objectToSerialize, typeof(T));
}
/// <summary>
/// Serializes object to XML representation.
/// </summary>
/// <exception cref="InvalidOperationException">
/// Is thrown when there was an error generating XML document. This can happen
/// for example if the object has string with invalid XML characters:
/// http://www.w3.org/TR/2004/REC-xml-20040204/#charsets.
/// See this article for other potential issues:
/// http://msdn.microsoft.com/en-us/library/aa302290.aspx
/// </exception>
public static Stream Serialize(object objectToSerialize, Type type) {
var stream = new MemoryStream();
XmlWriter writer = XmlWriter.Create(stream, _xmlSettings);
var x = new XmlSerializer(type);
x.Serialize(writer, objectToSerialize, _customNamespace);
stream.Position = 0;
return stream;
}
}
[WebDispatchFormatterConfiguration("application/xml")]
[WebDispatchFormatterMimeType(typeof(NamespacelessXmlFormatter), "application/xml")]
[XmlSerializerFormat(Use = OperationFormatUse.Literal, Style = OperationFormatStyle.Document)]
[OperationContract(Action = "http://www.YourNameSpace.com/ActionName",ReplyAction = "http://www.YourNameSpace.com/ActionName")]