Search code examples
asp.net-mvcasp.net-web-apihttpclientmime-typesdotnet-httpclient

Why do I get a 404 when trying to post content from a zip file vs a normal text file?


I have an MVC cross Web API app that has an ApiFileController, headed:

[Produces("application/json")]
[Route("api/File")]
public class ApiFileController : ApiBaseController

It has the following action method

[HttpPost("PostDir")]
[DisableRequestSizeLimit]
public async Task<IActionResult> PostDir(string serverPath)
{
    using (var fileStream = new FileStream(serverPath, FileMode.Create, FileAccess.Write))
    {
        await Request.Body.CopyToAsync(fileStream);
    }

    return Ok();
}

that is supposed to received a zipfile containing a directory, and unzip it into the serverPath parameter. Yet when I try and post a file as follows:

sourcePath = Path.Combine("Temp", Guid.NewGuid() + ".zip");
System.IO.Compression.ZipFile.CreateFromDirectory(localPath, sourcePath, CompressionLevel.Fastest, true);
...
using (var fileStream = File.Open(sourcePath, FileMode.Open, FileAccess.Read))
{
    using (var reader = new StreamReader(fileStream))
    using (var content = new StreamContent(reader.BaseStream))
    {
        var uri = $"api/File/PostDir?serverPath={WebUtility.UrlEncode(serverPath)}";
        var resp = await _client.PostAsync(uri, content);
        resp.EnsureSuccessStatusCode();
    }
}

I get a 404 - Not found. If I post a plain text file, as follows,

    using (var fileStream = File.Open(localPath, FileMode.Open, FileAccess.Read))
    {
        using (var reader = new StreamReader(fileStream))
        using (var content = new StreamContent(reader.BaseStream))
        {
            var uri = $"api/File/PostDir?serverPath={WebUtility.UrlEncode(serverPath)}";
            var resp = await _client.PostAsync(uri, content);
            resp.EnsureSuccessStatusCode();
        }
    }

where localPath points to a plain text file, the PostDir action is correctly invoked and properly saves the text file.

I am using HttpClient, in a wrapper class, to make the requests, and it is initialized in the wrapper's ctor as follows:

public ApiClient()
{
    var baseAddress = ConfigurationManager.AppSettings["ApiUrl"];
    _client = new HttpClient();
    _client.BaseAddress = new Uri(baseAddress);
    _client.DefaultRequestHeaders.Clear();
    _client.DefaultRequestHeaders.ConnectionClose = false;
    _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}

I suspect that when posting the binary zip files, I am missing a content type header or such. What am I doing wrong?


Solution

  • Don't take my code as gospel on how to upload a zip file, but it turns out the error was that I had only used the [DisableRequestSizeLimit] attribute on the action method, and that only disables Kestrel's request size limit. IIS still has a 30MB limit which I disabled by adding a web.config with the following:

    <system.webServer>
      <security>
        <requestFiltering>
          <!-- 1 GB -->
          <requestLimits maxAllowedContentLength="1073741824" />
        </requestFiltering>
      </security>
    </system.webServer>