从WCF restful响应中删除xml名称空间

从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

我使用WCF将一个普通的旧XML(POX)文档返回给调用者。我正在使用XML序列化器格式化程序将对象转换为XML

在返回的文档中,我有一些与xml模式和实例无关的xml名称空间引用(ASMX版本中没有)。我在网上看到了各种各样的论点,这些论点不应该被删除,我不相信这些论点会返回一个普通的XML文档

从WCF中返回的XML文档中删除这些xmlns引用的最简单方法是什么

签名看起来像:

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")]