DataStreamProvider
のマルチパート コンテンツから FormData を解析するためのロジックを複製するカスタムを実装することにより、それほどクリーンではない方法でこれを実現できますMultipartFormDataStreamProvider
。
ファイルをディスクに保存するだけでなく、マルチパート データを含む多くのタスクに役立つため、少なくとも FormData コレクションを識別して公開するコードを抽出せずに、MultipartFormDataStreamProvider
からサブクラス化する決定が下された理由はよくわかりません。MultiPartFileStreamProvider
とにかく、次のプロバイダーが問題の解決に役立つはずです. プロバイダーのコンテンツを反復するときに、ファイル名を持たないものはすべて無視していることを確認する必要があります (具体的にはstreamProvider.Contents.Select()
、フォームデータを DB にアップロードしようとするリスクがある else ステートメント)。したがって、プロバイダーに要求するコードは 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>