2012-05-03 32 views
12

Mi manca un trucco con il nuovo webapi - Sto provando a inviare una stringa xml attraverso una richiesta di posta e non ho molta fortuna.ASP.NET MVC4 WebAPI e inserimento dati XML

Il frontale sta usando jQuery in questo modo:

$(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); 
      } 
     }); 
    }); 
}); 

mio controller è abbastanza semplice in questo momento - solo il valore predefinito per l'azione post - cercando di restituire ciò che è stato passato in:

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

Tuttavia, "valore" è ripetutamente nullo. La cosa strana è, quando cambio i miei dati nel jquery per essere qualcosa di simile:

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

poi mi "valore" nel mio controller come 1234.

Come posso ottenere l'accesso al più stringa xml complessa nel mio controller?

risposta

13

Si sta inviando il tipo di contenuto di text/xml ma il parametro è stato definito come string. Idealmente il tuo XML dovrebbe essere mappato su una classe in modo che possa essere deserializzato.

Quindi, se è necessario xml crudo, non è ancora supportato. L'API Web attualmente è predisposta per la serializzazione di MediaTypeFormatters e manca di semplici formattatori di tipi, ma possono essere facilmente costruiti.

Questo è un minimo attuazione di tale formattatore supportante letto solo nel case e riferiscono al beta installatore (e non il codice sorgente notte in quanto è sostanzialmente cambiata):

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; 
    } 
} 

E usarlo, basta aggiungerlo alla collezione formattatori:

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

È possibile semplificare la lettura del flusso con '' 'var reader = new StreamReader (readStream); var text = attende reader.ReadToEndAsync();' '' –

6

Chiunque cerchi una versione aggiornata della risposta di Aliostad sopra dalla versione beta alla la RC di asp.net mvc 4 web api (piccole modifiche hanno comportato una leggera rilavorazione per me).

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

posso parlarti nella chat? – medBo

18

Di seguito vi permetterà di leggere un messaggio XML grezzo attraverso un posto a un metodo Web API:

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

È possibile eseguire il debug e ispezionare il corpo, intestazioni, ecc e vedrà la XML non elaborato pubblicato. Ho usato Fiddler's Composer per fare un POST HTTP e questo funziona bene.

+0

Esattamente quello che stavo cercando! Molte grazie !!! – MissRaphie

0

Che ha risolto il problema per me è stata l'aggiunta di questa:

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

(SubscriberController è la mia classe che estende ApiController, e il sopra è un costruttore statico, quindi verrà eseguito una sola volta).

Non sono sicuro se anche necessario, ma ho aggiunto l'attributo [FromBody] al mio parametro, in questo modo:

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

Il bello di fare in questo modo è che si può gestire senza problemi sia XML e di ingresso JSON .