web-dev-qa-db-fra.com

La longueur maximale du corps en plusieurs parties a dépassé l'exception

Bien qu'ayant défini MaxRequestLength et maxAllowedContentLength sur les valeurs maximales possibles dans la section web.config, ASP.Net Core ne me permet pas de télécharger des fichiers de taille supérieure à 134,217,728 Bytes. L'erreur exacte venant du serveur web est:

Une exception non gérée s'est produite lors du traitement de la demande.

InvalidDataException: limite de longueur de corps en plusieurs parties 134217728 dépassée.

Est-il possible de contourner ce problème? ( ASP.Net Core )

23
Transcendent

J'ai trouvé la solution à ce problème après avoir lu quelques articles dans GitHub. La conclusion est qu'ils doivent être définis dans la classe Startup. Par exemple:

public void ConfigureServices(IServiceCollection services)
{
        services.AddMvc();
        services.Configure<FormOptions>(x => {
            x.ValueLengthLimit = int.MaxValue;
            x.MultipartBodyLengthLimit = int.MaxValue; // In case of multipart
        })
 }

Cela résoudra le problème. Cependant, ils ont également indiqué qu'il existe un attribut [RequestFormSizeLimit], mais je n'ai pas encore été en mesure de le référencer. 

61
Transcendent

au cas où quelqu'un rencontrerait encore ce problème, j'ai créé un middleware qui intercepte la requête et crée un autre organe 

public class FileStreamUploadMiddleware  {
   private readonly RequestDelegate _next;

public FileStreamUploadMiddleware(RequestDelegate next)
{
  _next = next;
}

public async Task Invoke(HttpContext context)
{
  if (context.Request.ContentType != null)
  {
    if (context.Request.Headers.Any(x => x.Key == "Content-Disposition"))
    {
      ContentDispositionHeaderValue v = ContentDispositionHeaderValue.Parse(context.Request.Headers.First(x => x.Key == "Content-Disposition").Value);
      if (HasFileContentDisposition(v))
      {

        var memoryStream = new MemoryStream();
        context.Request.Body.CopyTo(memoryStream);
        var length = memoryStream.Length;
        var formCollection = context.Request.Form =
          new FormCollection(new Dictionary<string, StringValues>(),
          new FormFileCollection() { new FormFile(memoryStream, 0, length, v.Name, v.FileName) });



      }

    }

  }

  await _next.Invoke(context);
}

#region Helper

public static bool HasFileContentDisposition(ContentDispositionHeaderValue contentDisposition)
{
  // this part of code from  https://github.com/aspnet/Mvc/issues/7019#issuecomment-341626892
  return contentDisposition != null
         && contentDisposition.DispositionType.Equals("form-data")
         && (!string.IsNullOrEmpty(contentDisposition.FileName)
             || !string.IsNullOrEmpty(contentDisposition.FileNameStar));
}
#endregion 
 }

et dans le contrôleur, nous pouvons récupérer les fichiers de la demande 

   [HttpPost("/api/file")]
public IActionResult GetFile([FromServices] IHttpContextAccessor contextAccessor, [FromServices] IHostingEnvironment environment)
{
  //save the file
  var files = Request.Form.Files;
  foreach (var file in files)
  {
    var memoryStream = new MemoryStream();
    file.CopyTo(memoryStream);

    var fileStream = global::System.IO.File.Create($"{environment.WebRootPath}/images/background/{file.FileName}", (int)file.Length, FileOptions.None);
    fileStream.Write(memoryStream.ToArray(), 0, (int)file.Length);

    fileStream.Flush();
    fileStream.Dispose();

    memoryStream.Flush();
    memoryStream.Dispose();
  }
  return Ok();
  }

vous pouvez améliorer le code selon vos besoins, par exemple: ajoutez des paramètres de formulaire dans le corps de la demande et désérialisez-le.

c'est une solution de contournement je suppose, mais le travail est fait. 

0
M.Nour Berro