utiliza - xmlnamespacemanager
Elimina los espacios de nombres xml de la respuesta tranquila de WCF (9)
En mi servicio RESTful WCF que escribí antes del kit de inicio WCF RESTful, hice lo siguiente, que me proporciona resultados agradables y limpios.
Primero, asegúrese de que el comportamiento del punto final webHttp esté establecido:
<endpointBehaviors>
<behavior name="Web">
<webHttp/>
</behavior>
</endpointBehaviors>
Su punto final debe verse más o menos así (menos el contrato por simplicidad):
<endpoint address="" binding="webHttpBinding" behaviorConfiguration="Web" />
Mi contrato de servicio tiene estos contratos de operación:
[WebGet(UriTemplate="tasks", ResponseFormat=WebMessageFormat.Xml )]
[OperationContract]
Task[] GetTasks();
[WebGet(UriTemplate="tasks/{id}", ResponseFormat=WebMessageFormat.Xml)]
[OperationContract]
Task GetTask(string id);
La implementación del servicio en sí no tiene nada de especial. Puede intentar cambiar el WebMessageFormat pero el único otro elemento en la enumeración es "json".
Estoy usando WCF para devolver un documento simple XML anterior (POX) a la persona que llama. Estoy usando el formateador XML Serializer para convertir los objetos en XML.
En el documento devuelto tengo algunas referencias de espacio de nombres xml extraños (que no estaban allí en la versión ASMX) para el esquema XML y la instancia. He visto varios argumentos en la web que no deberían eliminarse, y no los compre para devolver un documento XML simple.
¿Cuál es la forma más sencilla de eliminar estas referencias xmlns de un documento XML devuelto en WCF?
La firma se ve así:
public ResponseInfo Process(string input) {
}
Supongo que lo intentas en lugar de obtener algo como esto al comienzo de tu xml:
<ResponseInfo
xmlns="http://schemas.datacontract.org/2004/07/ResponseInfo"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance" >
Quieres solo:
<ResponseInfo>
Tristemente, no he visto una manera fácil de eliminar esos campos. Buscaba soluciones en Google y la mayoría de las opciones para eliminarlo requieren la creación de su propio inspector de mensajes o su propio codificador.
Puede eliminar el espacio de nombres XML configurando el parámetro Espacio de nombres del atributo DataContract en una cadena vacía, como se muestra a continuación:
[DataContract(Namespace = "")]
public class ResponseInfo
{
// ...
}
Espero que esto ayude...
Si desea cambiar Xml, una de las maneras es usar una XslTransform. Tuve un caso similar, donde necesitaba eliminar los atributos xmlns de una solicitud Xml Post.
En WCF puede ''interceptar'' los mensajes Xml antes de la salida, o antes de que se procesen al entrar, implementando el IClientMessageInspector o el IDispatchMessageInspector, dependiendo de si necesita esto en el lado del cliente o del servidor.
Por ejemplo, para quitar los atributos del espacio de nombres de un mensaje Xml saliente a un servicio web, implementé el IClientMessageInspector, usando el siguiente código:
#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
y usó la siguiente transformación:
<?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>
Espero que esto sea útil.
Solo para dar la otra perspectiva, si el espacio de nombres es exclusivo de su proyecto, por ejemplo:
entonces debería ser retenido.
Tales espacios de nombres son la mejor práctica, agregarán menos de 1 línea de repetición a cualquier llamada XPath (que puede convertirse en un método auxiliar) y requerirán aproximadamente 15 líneas de código auxiliar para generar un prefijo / mapa URI, pero ese es el SOLO inconveniente y no siempre lo encontrará.
A cambio, obtienes nombres inequívocos para cada elemento y eso significa que puedes componer espacios de nombres de terceros con impunidad, por ejemplo, en teoría, puedes devolver XHTML directamente sin codificación de nivel de aplicación.
Es poco probable que surjan otros espacios de nombres, ya que es poco probable que se usen en cualquiera de las etiquetas que definió en su proyecto. De hecho, si lo son, entonces hay un error en alguna parte. La explicación probable de su existencia es que el marco los agregó solo en caso de que necesite agregar un elemento en algún lugar debajo del lugar donde se declaran, que puede no ser una ubicación que deba preocuparse.
Otra respuesta mencionó http://www.w3.org/2001/XMLSchema-instance que es un poco especial, quizás podría decir qué espacios de nombres se agregaron.
Yo tuve el mismo problema. Agregar BodyStyle: = WebMessageBodyStyle.Bare to WebInvoke funcionó para mí. La respuesta ya no está envuelta en metadatos.
No estoy seguro si esto ayudará, pero tuvimos un problema similar. En lugar de decorar miles de elementos de datos con los atributos DataContract / DataMember y usar el DataContractSerializer (predeterminado), descubrimos que si nuestro servicio WCF usara el XmlSerializerFormat, podríamos deserializar fácilmente nuestros objetos.
[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);
}
Así es como estamos deserializando los objetos:
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;
}
Encontré una buena solución a este problema que le permite inyectar su propio XmlSerializer en WCF que se utiliza al serializar y deserializar solicitudes. Este XmlSerializer se puede configurar para omitir espacios de nombres XML por completo (incluidos xmlns:i="w3.org/2001/XMLSchema-instance"
) o de cualquier otra manera que desee.
Mi solución utiliza WcfRestContrib . Casi podría usar el formateador de POX incluido, pero en nuestro caso queríamos admitir atributos, así que escribimos nuestro propio formateador simple.
Instrucciones:
1) Referencia WcfRestContrib desde tu proyecto.
2) Crear una implementación de 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);
}
}
}
}
Que utiliza un XmlSerializer que se adapta a sus necesidades (aquí está el nuestro que simplemente omite todos los espacios de nombres):
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;
}
}
3) Aplique los atributos WebDispatchFormatter...
a su servicio usando su implementación personalizada como tipo (según esta documentación ):
[WebDispatchFormatterConfiguration("application/xml")]
[WebDispatchFormatterMimeType(typeof(NamespacelessXmlFormatter), "application/xml")]
4) Aplique el atributo WebDispatchFormatter
a todos sus métodos de servicio (según esta documentación ).
5) Eso es todo. Pruebe su servicio y confirme que ahora se comporta como se esperaba.
Tengo el mismo problema cuando trabajo con clientes ASMX y para mí esto resuelve el problema:
Agregar a su interfaz de servicio:
[XmlSerializerFormat(Use = OperationFormatUse.Literal, Style = OperationFormatStyle.Document)]
Añadir a Operaciones:
[OperationContract(Action = "http://www.YourNameSpace.com/ActionName",ReplyAction = "http://www.YourNameSpace.com/ActionName")]