DataStreamProvider
您可以通过实现一个自定义来复制从多部分内容中解析 FormData 的逻辑,从而以一种不太干净的方式实现这一点MultipartFormDataStreamProvider
。
我不太清楚为什么决定MultipartFormDataStreamProvider
从MultiPartFileStreamProvider
没有至少提取标识和公开 FormData 集合的代码的情况下进行子类化,因为它对于涉及多部分数据的许多任务很有用,而不仅仅是将文件保存到磁盘。
无论如何,以下提供商应该可以帮助解决您的问题。您仍然需要确保在迭代提供程序内容时忽略任何没有文件名的内容(特别是streamProvider.Contents.Select()
您可能会尝试将表单数据上传到数据库的语句)。因此,询问提供者的代码是一个 HttpContent IsStream(),这有点小技巧,但最简单的是我能想到的。
请注意,它基本上是从源头剪切和粘贴斧头工作MultipartFormDataStreamProvider
- 它尚未经过严格测试(受此答案的启发)。
public class MultipartFormDataMemoryStreamProvider : MultipartMemoryStreamProvider
{
private readonly Collection<bool> _isFormData = new Collection<bool>();
private readonly NameValueCollection _formData = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
public NameValueCollection FormData
{
get { return _formData; }
}
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
if (parent == null) throw new ArgumentNullException("parent");
if (headers == null) throw new ArgumentNullException("headers");
var contentDisposition = headers.ContentDisposition;
if (contentDisposition != null)
{
_isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName));
return base.GetStream(parent, headers);
}
throw new InvalidOperationException("Did not find required 'Content-Disposition' header field in MIME multipart body part.");
}
public override async Task ExecutePostProcessingAsync()
{
for (var index = 0; index < Contents.Count; index++)
{
if (IsStream(index))
continue;
var formContent = Contents[index];
var contentDisposition = formContent.Headers.ContentDisposition;
var formFieldName = UnquoteToken(contentDisposition.Name) ?? string.Empty;
var formFieldValue = await formContent.ReadAsStringAsync();
FormData.Add(formFieldName, formFieldValue);
}
}
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 bool IsStream(int idx)
{
return !_isFormData[idx];
}
}
它可以按如下方式使用(使用 TPL 语法来匹配您的问题):
[HttpPost]
public Task<string> Post()
{
if (!Request.Content.IsMimeMultipartContent())
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "Invalid Request!"));
var provider = new MultipartFormDataMemoryStreamProvider();
return Request.Content.ReadAsMultipartAsync(provider).ContinueWith(p =>
{
var result = p.Result;
var myParameter = result.FormData.GetValues("myParameter").FirstOrDefault();
foreach (var stream in result.Contents.Where((content, idx) => result.IsStream(idx)))
{
var file = new FileData(stream.Headers.ContentDisposition.FileName);
var contentTest = stream.ReadAsByteArrayAsync();
// ... and so on, as per your original code.
}
return myParameter;
});
}
我使用以下 HTML 表单对其进行了测试:
<form action="/api/values" method="post" enctype="multipart/form-data">
<input name="myParameter" type="hidden" value="i dont do anything interesting"/>
<input type="file" name="file1" />
<input type="file" name="file2" />
<input type="submit" value="OK" />
</form>