2012-05-03 24 views
12

Me falta un truco con el nuevo webapi - Estoy tratando de enviar una cadena xml a través de una solicitud posterior y no tener mucha suerte.ASP.NET MVC4 WebAPI y publicación de datos XML

La parte delantera está utilizando jQuery así:

$(document = function() { 
    $("#buttonTestAPI").click(function() { 

     var d = " <customer><customer_id>1234</customer_id></customer>"; 
     $.ajax({ 
      type: 'POST', 
      contentType: "text/xml", 
      url: "@Url.Content("~/api/Customer/")", 
      data: d, 
      success: function (result) { 
       var str = result; 
       $("#output").html(str); 
      } 
     }); 
    }); 
}); 

Mi controlador es bastante simple en el momento - sólo el valor predeterminado para la acción post - tratar de devolver lo que se aprobó en:

public string Post(string value) 
    { 
     return value; 
    } 

Sin embargo, "valor" es repetidamente nulo. Lo curioso es que, cuando me cambio de datos en el jQuery a ser algo como esto:

d = "<customer_id>1234</customer_id>"; 

en cuando me siento "valor" en mi controlador como 1234.

¿Cómo puedo obtener acceso a la mayor cadena compleja de xml en mi controlador?

Respuesta

13

Está enviando el tipo de contenido de text/xml pero ha definido su parámetro como string. Lo ideal sería que su XML se asignara a una clase para que pueda ser deserializado.

Así que si necesita raw xml entonces no es compatible todavía. Actualmente, la API web está preparada para la serialización de MediaTypeFormatters y los formateadores de tipos simples que faltan, pero pueden construirse fácilmente.

Ésta es una mínima implementación de tales formateador que soporta solamente leer en su caso y en base a beta instalador (y no el código fuente de todas las noches, ya que ha cambiado sustancialmente):

public class TextMediaTypeFormatter : MediaTypeFormatter 
{ 
    public TextMediaTypeFormatter() 
    { 
     SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml")); 
     SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain")); 
     SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript")); 
    } 

    protected override bool CanReadType(Type type) 
    { 
     return type == typeof (string); 
    } 

    protected override System.Threading.Tasks.Task<object> OnReadFromStreamAsync(Type type, Stream stream, 
     HttpContentHeaders contentHeaders, 
     FormatterContext formatterContext) 
    { 
     var taskCompletionSource = new TaskCompletionSource<object>(); 
     try 
     { 
      var memoryStream = new MemoryStream(); 
      stream.CopyTo(memoryStream); 
      var s = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray()); 
      taskCompletionSource.SetResult(s); 
     } 
     catch (Exception e) 
     { 
      taskCompletionSource.SetException(e);   
     } 
     return taskCompletionSource.Task; 
    } 
} 

Y para usarlo, simplemente añadirlo a la colección formateadores:

GlobalConfiguration.Configuration.Formatters.Insert(0, new TextMediaTypeFormatter()); 
+0

Puede simplificar la lectura de la secuencia con '' 'var reader = new StreamReader (readStream); var text = await reader.ReadToEndAsync();' ' –

6

Cualquiera que busque una versión actualizada de la respuesta de Aliostad arriba del lanzamiento beta de el RC de asp.net mvc 4 web api (cambios menores resultaron en una ligera revisión para mí).

public class TextMediaTypeFormatter : MediaTypeFormatter 
{ 

    public TextMediaTypeFormatter() 
    { 
     SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml")); 
     SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain")); 
     SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript")); 
    } 

    public override bool CanReadType(Type type) 
    { 
     if (type == typeof(String)) 
      return true; 
     else 
      return false; 
    } 

    public override bool CanWriteType(Type type) 
    { 
     if (type == typeof(String)) 
      return true; 
     else 
      return false; 

    } 

    public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, System.Net.Http.HttpContent content, IFormatterLogger formatterLogger) 
    { 
     var taskCompletionSource = new TaskCompletionSource<object>(); 
     try 
     { 
      var memoryStream = new MemoryStream(); 
      readStream.CopyTo(memoryStream); 
      var s = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray()); 
      taskCompletionSource.SetResult(s); 
     } 
     catch (Exception e) 
     { 
      taskCompletionSource.SetException(e); 
     } 
     return taskCompletionSource.Task; 
    } 
} 
+0

¿puedo hablar con usted en el chat? – medBo

18

Lo siguiente le permitirá leer un mensaje XML sin procesar a través de un POST a un método de API Web:

public void PostRawXMLMessage(HttpRequestMessage request) 
{ 
    var xmlDoc = new XmlDocument(); 
    xmlDoc.Load(request.Content.ReadAsStreamAsync().Result); 
} 

puede depurar e inspeccionar el cuerpo, cabeceras, etc, y verá el XML sin procesar publicado. Utilicé Fiddler's Composer para hacer un HTTP POST y esto funciona bien.

+0

¡Exactamente lo que estaba buscando! Muchas gracias !!! – MissRaphie

0

Lo resolvió el problema para mí fue la adición de esto:

static SubscriberController() 
{ 
    //Needed for xml deserialization to work 
    var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter; 
    xml.UseXmlSerializer = true; 
} 

(SubscriberController es mi clase que se extiende ApiController, y lo anterior es un constructor estático, por lo que se ejecutará una vez).

No estoy seguro si también es necesario, pero he añadido el atributo [FromBody] a mi parámetros, así:

public async Task<HttpResponseMessage> SynchronizeImax([FromBody] SynchronizeRequest synchronizeRequest) 
{ 
    //... 
} 

Lo bueno de hacerlo de esta manera es que se puede manejar sin problemas tanto XML como entrada de JSON .

Cuestiones relacionadas