Search code examples
c#apiiisadministrationrefit

HttpRequestException in IIS Admin API


I want to edit the large file (Size ~ 50 MB) via Microsoft IIS Admin API and mentioned is the official documentation link (https://learn.microsoft.com/en-us/iis-administration/api/files#manipulating-file-content-apifilescontent).

Microsoft IIS Admin API has some limitations that it can't edit a file that is more than 30 MB in size so it needs to be done in chunks.

I am using the Refit library to make calls to IIS Admin.

var totalSize = content.Length;
                for (int i = 0; i < totalSize / 1000; i++)
                {
                    var lowerLimit = i == 0 ? 0 : 1000 * i;
                    var upperLimit = i == 0 ? 999 : i == totalSize / 1000 ? (totalSize % 1000 - 1) : (i+1)*1000 - 1;
                    var contentLength = i == totalSize/1000 ? totalSize % 1000 : 1000;
   

                  

                    var headers = new Dictionary<string, string> { { "Content-Length", $"{contentLength}" }, { "Content-Range", $"bytes {lowerLimit}-{upperLimit}/{totalSize}" } };
                    await _client.EditFileUnderDirectoryInChunks(content, fileId, AccessTokenHeaderValue, headers, cancellationToken).ConfigureAwait(false);
                }

Refit Client

 [Put("/api/files/content/{fileId}")]
        [Headers("Content-Type: application/octet-stream")]
        Task EditFileUnderDirectoryInChunks(
            [Body] Stream content,
            string fileId,
            [Header("Access-Token")] string accessToken, [HeaderCollection] IDictionary<string, string> headers,
            CancellationToken cancellationToken = default);

When my for loop runs it run successfully for the first iteration but in the second iteration I was getting below error

enter image description here


Solution

  • The issue is resolved now by sending the data in chunks and previously I was sending entire Stream data to edit file API method of IIS Admin API.

    Below is the final code

     if (content.Length > 25000000)  // Size Limit 25 MB
                {
                    var totalSize = content.Length;
                    var streamChunks = SplitStreamIntoChunks(content, 25000000).ToArray();
                    for (int i = 0; i <= totalSize / 25000000; i++)
                    {
                        var lowerLimit = i == 0 ? 0 : 25000000 * i;
                        var upperLimit = i == 0 ? (25000000 - 1) : i == totalSize / 25000000 ? ((i * 25000000) + (totalSize % 25000000 - 1)) : (i + 1) * 25000000 - 1;
                        var contentLength = i == totalSize / 25000000 ? totalSize % 25000000 : 25000000;
                        var contentRange = $"bytes {lowerLimit}-{upperLimit}/{totalSize}";
    
                        await _client.EditFileUnderDirectoryInChunks(new MemoryStream(streamChunks[i]), fileId, AccessTokenHeaderValue, 
                            contentLength, contentRange, cancellationToken).ConfigureAwait(false);
                    }
                }
    
    
    
    private static IEnumerable<byte[]> SplitStreamIntoChunks(Stream stream, int chunkSize)
            {
                var bytesRemaining = stream.Length;
                while (bytesRemaining > 0)
                {
                    var size = Math.Min((int)bytesRemaining, chunkSize);
                    var buffer = new byte[size];
                    var bytesRead = stream.Read(buffer, 0, size);
                    if (bytesRead <= 0)
                        break;
                    yield return buffer;
                    bytesRemaining -= bytesRead;
                }
            }