我曾经使用MultipartFormDataStreamProvider
来处理多部分请求。
由于我希望将上传的文件存储在内存中而不是磁盘文件中,因此我将代码更改为使用MultipartMemoryStreamProvider
。文件加载似乎工作正常,但我无法再访问
provider.FormData
下MultipartFormDataStreamProvider
提供的其他表单值。有人能告诉我怎么做吗?
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;
}
}
答案 0 :(得分:115)
2015年4月28日更新
您可以根据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();
}
答案 1 :(得分:1)
基于 Kiran 的出色回答,我汇总了 2015 年 4 月更新中的完整答案。似乎 WebAPI 中至少有一件事发生了变化,这让我一开始感到困惑。 provider.Files 不再存在,它是 .Content。因此,为了在不先将文件存储在磁盘上的情况下读取已发布的文件,您至少需要执行以下操作:
第 1 步:创建提供程序类
在你的项目中为这个类添加一个文件:
public class InMemoryMultipartFormDataProvider : MultipartFormDataRemoteStreamProvider
{
public override RemoteStreamInfo GetRemoteStream(HttpContent parent, HttpContentHeaders headers)
{
return new RemoteStreamInfo(
remoteStream: new MemoryStream(),
location: string.Empty,
fileName: string.Empty);
}
}
我相信这会将每个文件转换为内存流,而不是将其存储在磁盘上。
第 2 步:添加一个控制器动作来解析内容并创建流
在您的控制器中:
[HttpPost]
public async Task<IHttpActionResult> Upload()
{
// This endpoint only supports multipart form data
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
return StatusCode(HttpStatusCode.UnsupportedMediaType);
}
// read the content in a memory stream per file uploaded
var provider = await Request.Content.ReadAsMultipartAsync<InMemoryMultipartFormDataProvider>(new InMemoryMultipartFormDataProvider());
// iterate over each file uploaded and do something with the results
foreach (var fileContents in provider.Contents) {
processFileAsMemoryStream(await fileContents.ReadAsStreamAsync());
}
}