Web API:使用MultipartMemoryStreamProvider时如何访问多部分表单值?

我曾经使用MultipartFormDataStreamProvider来处理多部分请求。 由于我想上传的文件存储在内存中,而不是磁盘文件,我已经改变了我的代码使用MultipartMemoryStreamProvider。 加载文件似乎工作正常,但我不能再通过MultipartFormDataStreamProvider provider.FormData访问其他表单值。 有人能告诉我如何做到这一点?

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

我的控制器代码:

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

更新4/28/2015

您可以创build一个基于MultipartFormDataRemoteStreamProvider的自定义提供程序。
例:

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

更新

自定义内存中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; } } 

用法

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