foreach on Request.Files

75

Ich versuche, mehrere Dateien in ASP.NET MVC hochzuladen, und ich habe diese einfache foreach-Schleife in meinem Controller

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

Der vorherige Code generiert diesen Fehler:

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

Was ich nicht verstehe, ist, warum Request.Files [1] eine HttpPostedFileBase zurückgibt, aber wenn es wiederholt wird, gibt es Zeichenfolgen zurück (vermutlich die Dateinamen).

Hinweis: Ich weiß, dass dies mit einer for-Schleife gelöst werden kann. Außerdem habe ich versucht, HttpPostedFile mit demselben Fehler zu verwenden.

Omar
quelle

Antworten:

111

Der Enumerator auf HttpFileCollectiongibt die Schlüssel (Namen) der Dateien zurück, nicht die HttpPostedFileBaseObjekte. Wenn Sie den Schlüssel erhalten haben, verwenden Sie die Eigenschaft Item( []) mit dem Schlüssel (Dateiname), um das HttpPostedFileBaseObjekt abzurufen.

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

    ...
}
Tvanfosson
quelle
1
Gibt es eine Möglichkeit, stattdessen eine HttpPostedFile zurückzugeben?
Omar
Nicht, dass ich davon Wüste. Es leitet sich von NameObjectCollectionBase ab und der Enumerator für diese Klasse iteriert über die Schlüssel.
Tvanfosson
Der Compiler gibt einen Fehler für mich aus und möchte, dass ich ihn HttpPostedFileBaseanstelle von verwende HttpPostedFile.
Cody
@tvanfosson in meinem Fall wird Dateiname immer zu "Bild", aber wenn ich Request.Files [0] .FileName sage, gibt es dem richtigen Namen eine Idee? Ich benutze MVC5.
Geethanga
1
@Geethanga - Der "Name", der der Schlüssel ist, ist der Name auf dem HTML-Dateieingabe-Tag. Es ist nicht der Name der Datei, die hochgeladen wird.
Tvanfosson
36

Mit meinem Tab HTML ist:

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

Request.Files hat einen doppelten Namen im Array. Sie sollten also folgendermaßen lösen:

for (int i = 0; i < Request.Files.Count; i++ ){
    HttpPostedFileBase fileUpload = Request.Files[i];
nguyenhoai890
quelle
Dieser hat für mich besser funktioniert als die Antwort, da er, wie der HTML-Code hervorhebt, mehrere Dateien in derselben Dateieingabe zulässt.
Caffeinius
4
Dies ist die richtige Antwort, da Sie in der Lage sein sollten, den Dateinamen mit zu erhalten file.FileName. Wenn Sie dies mit foreachdoppelten Namen tun, wird die erste Datei mehrmals gespeichert
Arijoon
13

Wir können LINQ verwenden, um dies zu tun, und trotzdem foreach verwenden, wie gefragt:

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

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

Wie @tvanfosson sagte, gibt der Enumerator die Dateinamen als Zeichenfolgen zurück, nicht als HttpPostedFileBase. Diese Methode HttpPostedFileBase this[string name]gibt das gewünschte Objekt zurück. Wenn HttpFileCollectionBaseimplementiert IEnumerable<HttpPostedFileBase>, könnten wir das foreach normal machen. Es wird jedoch eine nicht generische implementiert IEnumerable.

Akira Yamamoto
quelle
6

Sie können versuchen, die Zeichenfolgen zu iterieren und stattdessen wie folgt in HttpPostedFile umzuwandeln:

foreach (string file in Request.Files)
    {
        HttpPostedFile hFile = Request.Files[file] as HttpPostedFile;
        if (hFile.ContentLength > 0)
            FileUpload(hFile);
    }
Joe Barone
quelle
3
kann HttpPostedFileBase nicht implizit in HttpPostedFile konvertieren
Ifeanyi Chukwu
6

Leider hat die Antwort von tvanfosson bei mir nicht funktioniert. Obwohl die Dateien problemlos hochgeladen werden und kein Fehler ausgegeben wird, tritt ein Problem auf, bei dem nur eine der Dateien verwendet wird, sodass dieselbe Datei zweimal gespeichert wird, anstatt beide zu verwenden.

Es schien ein Problem mit der foreach-Anweisung zu sein, die die Namen jeder Datei in den Request.Files durchläuft. Aus irgendeinem Grund funktionierte sie für mich nicht als Schlüssel, und jedes Mal wurde nur die erste Datei ausgewählt.

HttpFileCollectionBase files = Request.Files;

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

    ...
}
Harvzor
quelle
Dies war ein Problem für uns unter iOS, da die Funktion "Foto aufnehmen" jede Datei "image.jpg" benennt - aber diese Änderung hat es behoben. Vielen Dank.
Brian Davis
4

Der folgende Code hat bei mir funktioniert.

  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;
}
Ivan DCosta
quelle
0

Sie können das HttpPostedFileaus der HttpFileCollectionVerwendung foreachwie folgt herausholen:

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