私はHttpClient
とWeb APIの間のファイル転送に非常に慣れていないので、コードの無知や当て推量を許してください。私はSystem.IO.Compression.ZipFile
で作成されたファイルをWeb APIに約1日投稿しようとしていますが、常に404応答が返されます。空のストリームで投稿すると、APIアクションメソッドが呼び出されるので、404はURIではなくコンテンツが原因であることがわかります。
このメソッドは、ファイルをポストしようとするクライアントWPFアプリケーションにあります。
public async Task PostDirAsync(string localDirPath, string serverDir)
{
var sourcePath = Path.Combine("Temp", Guid.NewGuid() + ".Zip");
ZipFile.CreateFromDirectory(localDirPath, sourcePath, CompressionLevel.Fastest, true);
StreamContent streamContent;
using (var fs = File.Open(sourcePath, FileMode.Open))
{
var outStream = new MemoryStream();
await fs.CopyToAsync(outStream);
outStream.Position = 0;
streamContent = new StreamContent(outStream);
}
streamContent.Headers.Add("Content-Type", "application/octet-stream");
var resp = await _client.PostAsync("api/File/PostDir?serverPath={WebUtility.UrlEncode(serverDir)}", streamContent);
}
そして、これは投稿を受け取るWeb APIのアクションメソッドですが、投稿を試みる前にoutStream.Position = 0;
を実行しない場合のみです。
[HttpPost("PostDir")]
[DisableRequestSizeLimit]
public async Task<IActionResult> PostDir(string serverPath)
{
var zipName = Path.Combine(_config["QuickDrive:TempDir"], Guid.NewGuid() + ".Zip");
using (var ms = new MemoryStream())
using (var fileStream = System.IO.File.Create(zipName))
{
await Request.Body.CopyToAsync(ms);
ms.Position = 0;
await ms.CopyToAsync(fileStream);
}
return Ok();
}
アクションメソッドが呼び出され、空のストリームでエラーなしで実行されますが、空のファイルを書き込むため、ほとんど役に立ちません。何が悪いのですか?
コメントで述べたように、最初の問題は、ファイルのコピーに関係するStream
インスタンスが_Stream.Position = 0
_を使用してリセットされていないことでした。すでにこれらの変更を行っていることは承知しておりますが、これは2つの部分からなるソリューションであることを強調したいだけです。
したがって、2番目の部分:
サンプルコードでは、デフォルトのASP.NET Core 2.0+ Kestrelリクエストの制限を回避するために_[DisableRequestSizeLimit]
_アノテーションを追加しました。ただし、IISによって課される制限もあります。デフォルトでは30MBです。このサイズ制限を超えると、IIS自体が404応答を生成します。これが表示されています。
この答え は、カスタム_Web.config
_を使用してこの制限を変更する方法を説明します(完全を期すために以下に含まれています)。
_<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<security>
<requestFiltering>
<!-- 1 GB -->
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
</system.webServer>
</configuration>
_
余談ですが、
特定の理由がない限り、コードでMemoryStream
を使用せず、fs
を直接new StreamContent(...)
に渡すだけで済みます。 _Request.Body
_ストリームを使用して同様のことを行い、それを出力FileStream
に直接コピーできます。これは次のようになります:
_public async Task PostDirAsync(string localDirPath, string serverDir)
{
var sourcePath = Path.Combine("Temp", Guid.NewGuid() + ".Zip");
ZipFile.CreateFromDirectory(localDirPath, sourcePath, CompressionLevel.Fastest, true);
var streamContent = new StreamContent(File.Open(sourcePath, FileMode.Open));
streamContent.Headers.Add("Content-Type", "application/octet-stream");
var resp = await _client.PostAsync("api/File/PostDir?serverPath={WebUtility.UrlEncode(serverDir)}", streamContent);
}
_
そして:
_[HttpPost("PostDir")]
[DisableRequestSizeLimit]
public async Task<IActionResult> PostDir(string serverPath)
{
var zipName = Path.Combine(_config["QuickDrive:TempDir"], Guid.NewGuid() + ".Zip");
using (var fileStream = System.IO.File.Create(zipName))
await Request.Body.CopyToAsync(fileStream );
return Ok();
}
_