.Net でクライアントから WebAPI に対しPOSTリクエストで複数のファイルをアップロードし、サーバからのレスポンスで複数ファイルをダウンロードする必要があったのでやってみた。
クライアントからのPOSTは HttpClient を使用する想定。
サーバサイドは ASP .Net MVC 4 WebAPI のPOSTでマルチパートのファイルを送受信する を参照。
やりたいこと
POST リクエスト
ローカルに保存されたファイルを MultiPart の Content にして送信する
サーバからのレスポンス
MultiPart でファイルが格納された Content をローカルに保存する
リクエストにファイルを含めて送る
送信側はネット上を調べたら比較的簡単にできた。
MultiPart の Content を作るには MultipartFormDataContent を生成し、File Content をAddしていく流れ。
var content = new MultipartFormDataContent();
File Content は File.OpenRead()で開いたファイルを StreamContent に食わせて Header にファイル名を設定してあげる。
var fileName = @"C:¥hogehoge.txt";
var fileContent = new StreamContent(File.OpenRead(fileName));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = Path.GetFileName(fileName)
};
content.Add(fileContent); // これをファイル数分繰り返す
あとは HttpClient の PostAsync() で送るだけ。
var httpClient = new HttpClient();
HttpResponseMessage response = httpClient.PostAsync(this.url, content).Result;
レスポンスからファイルを読み込む
今度はサーバから返ってきたレスポンスに MultiPart のファイルが含まれている場合に読み込んでローカルに保存する。ネット上にもなかなかまとまった情報がなくて苦労した。
MultiPart の読み込みには HttpContentMultipartExtensions という拡張メソッドを使うのがミソ。(.Net4.5 以上が必要っぽい)
参照設定の[アセンブリ][拡張] から「System.Net.Http.Formatting」を追加する。
まず HttpContentMultipartExtensions.ReadAsMultipartAsync() でレスポンスに渡された Content を provider に読み込む。
var provider = HttpContentMultipartExtensions.ReadAsMultipartAsync(response.Content).Result;
次に provider に読み込まれた Contents を1つずつ取り出す。
Content を取り出してしまえば、ReadAsStreamAsync() を呼び出してファイルの Stream を取得する。
保存用のファイルStreamを別途開き、CopyTo() でローカルに保存する。
foreach (var responseContent in provider.Contents)
{
var fileName = responseContent.Headers.ContentDisposition.FileName;
Stream stream = responseContent.ReadAsStreamAsync().Result;
using (var outFileStream = new FileStream(@"C:\hoge" + Path.DirectorySeparatorChar + fileName, FileMode.Create, FileAccess.Write))
{
stream.CopyTo(outFileStream);
}
}
上記例ではファイル決め打ちで処理しているが、いろいろ混ざっている場合は ContentType などを見てよしなに判断する。
ただ、ファイルの場合は ContentType が null なのでいきなり見ないように注意する。
if (responseContent.Headers.ContentType != null && responseContent.Headers.ContentType.ToString().Contains("text/plain"))
{
// テキストのパラメータ
string key = responseContent.Headers.ContentDisposition.Name;
string value = responseContent.ReadAsStringAsync().Result;
}
書いてみるとたったこれだけの事か。。
特にクライアントサイドで MultiPart から Content を取り出す方法がなかなかわからなかったんだけど、わかってしまえば大したことはないな。