web-dev-qa-db-fra.com

foreach on Request.Files

J'essaie de télécharger plusieurs fichiers dans ASP.NET MVC et j'ai cette boucle foreach simple dans mon contrôleur

foreach (HttpPostedFileBase f in Request.Files)
{
    if (f.ContentLength > 0)
        FileUpload(f);
}

Le code précédent génère cette erreur:

Unable to cast object of type 'System.String' to type 'System.Web.HttpPostedFile'. 

Ce que je ne comprends pas, c'est pourquoi Request.Files [1] renvoie un HttpPostedFileBase mais quand il est itéré, il retourne des chaînes (vraisemblablement les noms de fichiers).

Remarque: je sais que cela peut être résolu avec une boucle for. J'ai également essayé d'utiliser HttpPostedFile, avec la même erreur.

65
Omar

L'énumérateur sur le HttpFileCollection renvoie les clés (noms) des fichiers, pas les objets HttpPostedFileBase. Une fois que vous avez obtenu la clé, utilisez le Item ([]) avec la clé (nom de fichier) pour obtenir l'objet HttpPostedFileBase.

foreach (string fileName in Request.Files)
{
    HttpPostedFileBase file = Request.Files[fileName];

    ...
}
100
tvanfosson

Avec mon onglet HTML c'est:

<input class="valid" id="file" name="file" multiple="" type="file">

Request.Files aura un nom en double dans le tableau. Vous devez donc résoudre comme ceci:

for (int i = 0; i < Request.Files.Count; i++ ){
    HttpPostedFileBase fileUpload = Request.Files[i];
29
nguyenhoai890

Nous pouvons utiliser LINQ pour ce faire et toujours utiliser foreach comme demandé:

var files = Enumerable.Range(0, Request.Files.Count)
    .Select(i => Request.Files[i]);

foreach (var file in files)
{
    // file.FileName
}

Comme l'a dit @tvanfosson, l'énumérateur renvoie les noms de fichiers sous forme de chaînes, pas le HttpPostedFileBase. Cette méthode HttpPostedFileBase this[string name] renvoie l'objet que nous voulons. Si HttpFileCollectionBase implémenté IEnumerable<HttpPostedFileBase> alors nous pourrions faire le foreach normalement. Cependant, il implémente un IEnumerable non générique.

10
Akira Yamamoto

Vous pouvez essayer d'itérer les chaînes et de les convertir en HttpPostedFile à la place, comme ceci:

foreach (string file in Request.Files)
    {
        HttpPostedFile hFile = Request.Files[file] as HttpPostedFile;
        if (hFile.ContentLength > 0)
            FileUpload(hFile);
    }
6
Joe Barone

Malheureusement, la réponse de tvanfosson n'a pas fonctionné pour moi. Bien que les fichiers soient téléchargés très bien et qu'aucune erreur ne soit générée, un problème se produirait lorsqu'un seul des fichiers serait utilisé, donc le même fichier serait enregistré deux fois plutôt que de les utiliser tous les deux.

Cela semblait être un problème avec l'instruction foreach qui parcourait les noms de chaque fichier dans les fichiers Request.Files, pour une raison quelconque, cela ne fonctionnait pas comme une clé pour moi, et seul le premier fichier serait sélectionné à chaque fois.

HttpFileCollectionBase files = Request.Files;

for(var i = 0; i < files.Count; i++)
{
    HttpPostedFileBase file = files[i];

    ...
}
4
Harvey

Le code suivant a fonctionné pour moi.

  HttpResponseMessage result = null;
  var httpRequest = System.Web.HttpContext.Current.Request;
  HttpFileCollection uploadFiles = httpRequest.Files;
  var docfiles = new List<string>();

  if (httpRequest.Files.Count > 0){
      int i;
      for (i = 0; i < uploadFiles.Count; i++) {
          HttpPostedFile postedFile = uploadFiles[i];
          var filePath = @"C:/inetpub/wwwroot/test1/reports/" + postedFile.FileName;
          postedFile.SaveAs(filePath);
          docfiles.Add(filePath);
      }
      result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
  } else {
      result = Request.CreateResponse(HttpStatusCode.BadRequest);
  }

  return result;
}
4
Ivan DCosta

Vous pouvez extraire le HttpPostedFile du HttpFileCollection en utilisant foreach comme ceci:

foreach (var obj in fileCollection)
{
    HttpPostedFile file = fileCollection.Get(obj.ToString());
}
0
Jnr