2013-06-12 2 views
43

Ich verwendete MultipartFormDataStreamProvider, um mehrteilige Anforderungen zu verarbeiten. Da ich die hochgeladene Datei im Speicher anstatt einer Datei speichern möchte, habe ich meinen Code geändert, um MultipartMemoryStreamProvider zu verwenden. Das Laden der Datei scheint gut zu funktionieren, aber ich bin nicht mehr in der Lage, auf andere Formularwerte zuzugreifen, die über provider.FormData unter MultipartFormDataStreamProvider verfügbar waren. Könnte mir jemand zeigen, wie man das macht?Web-API: Wie kann man auf mehrteilige Formularwerte zugreifen, wenn MultipartMemoryStreamProvider verwendet wird?

Die rohe Anfrage von Fiddler erfasst:

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

Mein Controller-Code:

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

Antwort

108

Aktualisiert 4/28/2015

Sie könnten einen benutzerdefinierten Anbieter erstellen basierend auf MultipartFormDataRemoteStreamProvider .
Beispiel:

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

Aktualisiert

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

Nutzungs:

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

Danke Kiran für die Eingabe. Wenn ich versuche, was Sie vorgeschlagen haben, scheint es, die Zeile nicht zu mögen NameValueCollection nvc = erwarten content.ReadAsFormDataAsync(); aus irgendeinem Grund. Ich erhalte einen Fehler:. "ExceptionMessage: Es ist kein MediaTypeFormatter verfügbar, um ein Objekt vom Typ 'FormDataCollection' aus einem Inhalt mit dem Medientyp 'multipart/form-data' zu lesen". Irgendwelche Ideen? – user2434400

+0

Ist dieser "Inhalt" genau so, wie ich oben erwähnt habe, das ist der Inhalt des Inhaltsarrays? Ich frage dies, weil Sie versuchen, den Inhalt der gesamten Anfrage zu lesen, anstatt den inneren Inhalt –

+0

Ich versuchte beide: nvc = Request.Content.ReadAsFormDataAsync(). Ergebnis; und nvc = provider.Contents [0] .ReadAsFormDataAsync(). Result; Aber ich bekomme ähnliche Fehler. – user2434400

Verwandte Themen