2013-06-12 15 views
43

Ho usato MultipartFormDataStreamProvider per elaborare richieste multipart. Poiché desidero che il file caricato sia archiviato in memoria, anziché un file su disco, ho modificato il mio codice per utilizzare MultipartMemoryStreamProvider. Il caricamento dei file sembra funzionare correttamente ma non sono più in grado di accedere a altri valori del modulo che erano disponibili tramite provider.FormData in MultipartFormDataStreamProvider. Qualcuno potrebbe mostrarmi come farlo?: come accedere ai valori dei moduli multipart quando si utilizza MultipartMemoryStreamProvider?

La richiesta grezzo catturato dai Fiddler:

POST http://myserver.com/QCCSvcHost/MIME/RealtimeTrans/ HTTP/1.1 
Content-Type: multipart/form-data; boundary="XbCY" 
Host: na-w-lxu3 
Content-Length: 1470 
Expect: 100-continue 
Connection: Keep-Alive 

--XbCY 
Content-Type: text/plain; charset=utf-8 
Content-Disposition: form-data; name=PayloadType 

X12_270_Request_005010X279A1 
--XbCY 
Content-Type: text/plain; charset=utf-8 
Content-Disposition: form-data; name=ProcessingMode 

RealTime 
--XbCY 
Content-Type: text/plain; charset=utf-8 
Content-Disposition: form-data; name=PayloadID 

e51d4fae-7dec-11d0-a765-00a0c91e6fa6 
--XbCY 
Content-Type: text/plain; charset=utf-8 
Content-Disposition: form-data; name=TimeStamp 

2007-08-30T10:20:34Z 
--XbCY 
Content-Type: text/plain; charset=utf-8 
Content-Disposition: form-data; name=SenderID 

HospitalA 
--XbCY 
Content-Type: text/plain; charset=utf-8 
Content-Disposition: form-data; name=ReceiverID 

PayerB 
--XbCY 
Content-Type: text/plain; charset=utf-8 
Content-Disposition: form-data; name=CORERuleVersion 

2.2.0 
--XbCY 
Content-Disposition: form-data; name=Payload; filename=276_5010.edi 

ISA*00*~SE*16*0001~GE*1*1~IEA*1*191543498~ 
--XbCY-- 

Il mio codice di controllo:

string payload = null; 
NameValueCollection nvc = null; 
string fname = null; 
StringBuilder sb = new StringBuilder(); 
sb.AppendLine(); 
foreach (StreamContent item in provider.Contents) 
{ 
    fname = item.Headers.ContentDisposition.FileName; 
    if (!String.IsNullOrWhiteSpace(fname)) 
    { 
     payload = item.ReadAsStringAsync().Result; 
    } 
    else 
    { 
     nvc = item.ReadAsFormDataAsync().Result; 
    } 
} 

risposta

108

Aggiornato 4/28/2015

Si potrebbe creare un provider personalizzato basato sulla MultipartFormDataRemoteStreamProvider .
Esempio:

public class CustomMultipartFormDataProvider : MultipartFormDataRemoteStreamProvider 
{ 
    public override RemoteStreamInfo GetRemoteStream(HttpContent parent, HttpContentHeaders headers) 
    { 
     return new RemoteStreamInfo(
      remoteStream: new MemoryStream(), 
      location: string.Empty, 
      fileName: string.Empty); 
    } 
} 

Aggiornato

In-memory MultiaprtFormDataStreamProvider:

public class InMemoryMultipartFormDataStreamProvider : MultipartStreamProvider 
{ 
    private NameValueCollection _formData = new NameValueCollection(); 
    private List<HttpContent> _fileContents = new List<HttpContent>(); 

    // Set of indexes of which HttpContents we designate as form data 
    private Collection<bool> _isFormData = new Collection<bool>(); 

    /// <summary> 
    /// Gets a <see cref="NameValueCollection"/> of form data passed as part of the multipart form data. 
    /// </summary> 
    public NameValueCollection FormData 
    { 
     get { return _formData; } 
    } 

    /// <summary> 
    /// Gets list of <see cref="HttpContent"/>s which contain uploaded files as in-memory representation. 
    /// </summary> 
    public List<HttpContent> Files 
    { 
     get { return _fileContents; } 
    } 

    public override Stream GetStream(HttpContent parent, HttpContentHeaders headers) 
    { 
     // For form data, Content-Disposition header is a requirement 
     ContentDispositionHeaderValue contentDisposition = headers.ContentDisposition; 
     if (contentDisposition != null) 
     { 
      // We will post process this as form data 
      _isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName)); 

      return new MemoryStream(); 
     } 

     // If no Content-Disposition header was present. 
     throw new InvalidOperationException(string.Format("Did not find required '{0}' header field in MIME multipart body part..", "Content-Disposition")); 
    } 

    /// <summary> 
    /// Read the non-file contents as form data. 
    /// </summary> 
    /// <returns></returns> 
    public override async Task ExecutePostProcessingAsync() 
    { 
     // Find instances of non-file HttpContents and read them asynchronously 
     // to get the string content and then add that as form data 
     for (int index = 0; index < Contents.Count; index++) 
     { 
      if (_isFormData[index]) 
      { 
       HttpContent formContent = Contents[index]; 
       // Extract name from Content-Disposition header. We know from earlier that the header is present. 
       ContentDispositionHeaderValue contentDisposition = formContent.Headers.ContentDisposition; 
       string formFieldName = UnquoteToken(contentDisposition.Name) ?? String.Empty; 

       // Read the contents as string data and add to form data 
       string formFieldValue = await formContent.ReadAsStringAsync(); 
       FormData.Add(formFieldName, formFieldValue); 
      } 
      else 
      { 
       _fileContents.Add(Contents[index]); 
      } 
     } 
    } 

    /// <summary> 
    /// Remove bounding quotes on a token if present 
    /// </summary> 
    /// <param name="token">Token to unquote.</param> 
    /// <returns>Unquoted token.</returns> 
    private static string UnquoteToken(string token) 
    { 
     if (String.IsNullOrWhiteSpace(token)) 
     { 
      return token; 
     } 

     if (token.StartsWith("\"", StringComparison.Ordinal) && token.EndsWith("\"", StringComparison.Ordinal) && token.Length > 1) 
     { 
      return token.Substring(1, token.Length - 2); 
     } 

     return token; 
    } 
} 

Uso:

public async Task Post() 
{ 
    if (!Request.Content.IsMimeMultipartContent("form-data")) 
    { 
     throw new HttpResponseException(HttpStatusCode.BadRequest); 
    } 

    var provider = await Request.Content.ReadAsMultipartAsync<InMemoryMultipartFormDataStreamProvider>(new InMemoryMultipartFormDataStreamProvider()); 

    //access form data 
    NameValueCollection formData = provider.FormData; 

    //access files 
    IList<HttpContent> files = provider.Files; 

    //Example: reading a file's stream like below 
    HttpContent file1 = files[0]; 
    Stream file1Stream = await file1.ReadAsStreamAsync(); 
} 
+0

Grazie Kiran per l'input. Quando provo ciò che hai suggerito, non sembra che la riga NameValueCollection nvc = attenda content.ReadAsFormDataAsync(); per qualche motivo. Sto ricevendo errore:. "ExceptionMessage: No MediaTypeFormatter è disponibile per leggere un oggetto di tipo 'FormDataCollection' dal contenuto con tipo di supporto 'multipart/form-data'". Qualche idea? – user2434400

+0

Questo 'contenuto' è proprio come ho menzionato sopra, cioè il contenuto della matrice di contenuti? lo chiedo perché sembra che tu stia cercando di leggere il contenuto dell'intera richiesta piuttosto che il contenuto interno –

+0

Ho provato entrambi: nvc = Request.Content.ReadAsFormDataAsync(). Risultato; e nvc = provider.Contents [0] .ReadAsFormDataAsync(). Risultato; Ma sto ottenendo errori simili. – user2434400

Problemi correlati