Geschrieben von: Christoph Wille
Kategorie: ASP.NET
This printed page brought to you by AlphaSierraPapa
Etwas das unter ASP ohne Fremdkomponente nicht vernünftig möglich war ist das Uploaden von Dateien auf einen Webserver, obwohl die Verwendungsmöglichkeiten dieses Features vom Content-Managementsystem bis zu einem Kostenvoranschlagsservice für Übersetzungen (basierend auf dem Inhalt von upgeloadeten Dateien) reichen kann. Natürlich sind das nur zwei von vielen Anwendungsmöglichkeiten.
Wie gesagt, unter ASP benötigt man Fremdkomponenten, um mittels ASP Dateien am Webserver
entgegennehmen zu können. ASP.NET bietet diese Funktionalität mit einer HTML Control names
HtmlInputFile, die sich von der bereits bekannten
In diesem Artikel stelle ich zwei Anwendungsfälle des Dateiuploads vor:
Bei ersterem Ansatz handelt es sich um die einfachste Lösung, der zweite demonstriert ein sehr flexibles Konzept wie man die Daten des Uploads selbst in Empfang nehmen und weiterverarbeiten kann.
Voraussetzung um den Sourcecode dieses Artikels verwenden zu können ist eine Installation des Microsoft .NET Framework SDK's auf einem Webserver. Weiters setze ich voraus, daß der Leser die Programmiersprache C# zu einem gewissen Grad beherrscht - es finden sich etliche Artikel auf diesem Server, um das notwendige Wissen zu erlernen.
Sehen Sie sich den nachfolgenden Screenshot an - solche Beispiele dürften Ihnen vom Dateiupload unter ASP auch bereits bekannt sein.
Obwohl es von "außen" nicht viel anders aussieht, so passiert unter der Haube doch etwas deutlich anderes als wir es von ASP gewohnt sind. Dazu werden wir jetzt den Sourcecode genauer unter die Lupe nehmen (uploadNsave.aspx):
<% @Page Language="C#" %> <html> <head> <title>Dateiupload in ASP.NET</title> </head> <body bgcolor="#ffffff" style="font:8pt verdana;"> <script language="C#" runat="server"> void btnUploadTheFile_Click(object Source, EventArgs evArgs) { string strFileNameOnServer = txtServername.Value; string strBaseLocation = "c:\\temp\\"; if ("" == strFileNameOnServer) { txtOutput.InnerHtml = "Fehler - es muß ein Dateiname angegeben werden."; return; } if (null != uplTheFile.PostedFile) { try { uplTheFile.PostedFile.SaveAs(strBaseLocation+strFileNameOnServer); txtOutput.InnerHtml = "Datei erfolgreich nach <b>" + strBaseLocation+strFileNameOnServer+"</b> upgeloadet"; } catch (Exception e) { txtOutput.InnerHtml = "Fehler beim Speichern von <b>" + strBaseLocation+strFileNameOnServer+"</b><br>"+ e.ToString(); } } } </script> <table> <form enctype="multipart/form-data" runat="server"> <tr> <td>Datei auswählen:</td> <td><input id="uplTheFile" type=file runat="server"></td> </tr> <tr> <td>Name am Server:</td> <td><input id="txtServername" type="text" runat="server"></td> </tr> <tr> <td colspan="2"> <input type=button id="btnUploadTheFile" value="Speichern" OnServerClick="btnUploadTheFile_Click" runat="server"> </td> </tr> </form> </table> <span id=txtOutput style="font: 8pt verdana;" runat="server" /> </body> </html>
Betrachten wir für den Anfang nur das Formular, das die Datei (und den Namen, den sie am Server
erhalten soll) an den Server schickt. Da wir gemischte Daten schicken, ist der enctype auf
In diesem Formular verwende ich im Gegensatz zum Artikel On-the-fly Generierung von Graphiken keine Web Controls, sondern HTML Controls - deswegen sieht es auch sehr vertraut aus. Allerdings würde man unter ASP sicher nicht das finden:
<input type=button id="btnUploadTheFile" value="Speichern" OnServerClick="btnUploadTheFile_Click" runat="server">
Der Klick auf den Button löst am Server ein Event aus, das in der Funktion btnUploadTheFileFile_Click abgehandelt wird. Und somit sind wir beim Code, der notwendig ist, um eine Datei am Server erfolgreich abzuspeichern:
if (null != uplTheFile.PostedFile) { try { uplTheFile.PostedFile.SaveAs("c:\\temp\\file.bin"); txtOutput.InnerHtml = "Datei erfolgreich upgeloadet"; } catch (Exception e) { txtOutput.InnerHtml = "Fehler beim Speichern<br>"+ e.ToString(); } }
Das ist zwar nicht exakt der Sourcecode aus dem Beispiel, allerdings fehlt nur das "Rundherum" für die Namensvergabe am Server - der Fileupload funktioniert hier ebenso. Also was passiert? Die if Abfrage überprüft, ob eine Datei gepostet wurde, indem sie die Eigenschaft PostedFile gegen null vergleicht. Wird eine Datei upgeloadet, so hält diese Eigenschaft eine gültige Referenz auf ein Objekt vom Typ HttpPostedFile, und ist somit verschieden von null.
Nach diesem Sicherheitscheck bleibt uns "nur noch" die Datei zu speichern - ein simpler Aufruf der Funktion SaveAs auf dem Objekt HttpPostedFile erledigt alles für uns. Sollte etwas schiefgehen, wird unser Code darüber mit einer Exception benachrichtigt. So einfach ist es in ASP.NET eine Datei auf den Webserver zu laden.
Der Code im Beispiel selbst differiert nur dahingehend, daß die Datei einen benutzergewählten Namen erhalten kann. Dadurch ist er zwar etwas länger, aber bereits sehr flexibel. Der Weiterverwendung und Erweiterung in eigenen Projekten steht nichts im Wege.
So nett und schön das einfache Speichern der upgeloadeten Datei in eine Datei am Server auch sein kein, so oft möchte man mit den upgeloadeten Daten (den Bits) sofort wieder weiterarbeiten - ohne den Umweg in eine Datei. Anwendungsfälle wären etwa die Daten in die Datenbank zu speichern, die Daten zu parsen, oder irgendeine andere Bearbeitung durchzuführen.
Auch in diesem Fall läßt uns ASP.NET und das .NET Framework nicht im Stich. Anstatt die Kontrolle mit der SaveAs Funktion aus der Hand zu geben, kann man direkten Zugriff auf den Stream der upgeloadeten Daten bekommen und mit diesen sofort weiterarbeiten - während der Upload passiert.
Das Beispiel, das ich zu Demonstrationszwecken gebastelt habe, erfüllt derzeit nur einen Zweck: die upgeloadeten Daten werden aus dem Stream ausgelesen und in einer Stringvariablen zwischengespeichert - um dann einfach an den Client zurückgeschickt zu werden. Für Textuploads mag das bereits sinnvoll sein, bei binären Uploads (Bilder zum Beispiel) ist der Output nicht gerade überwältigend:
Der vorige Screenshot zeigt, daß mein Sourcecode (uploadNdump.aspx) auch mit binären Daten korrekt umgehen kann. Dies erreicht ich durch eine Zwangsumkonvertierung auf ASCII. Die Details dazu können Sie dem Sourcecode und der folgenden Beschreibung entnehmen.
<% @Page Language="C#" %> <% @Import Namespace="System.IO" %> <% @Import Namespace="System.Text" %> <html> <head> <title>Dateiupload in ASP.NET</title> </head> <body bgcolor="#ffffff" style="font:8pt verdana;"> <script language="C#" runat="server"> void btnUploadTheFile_Click(object Source, EventArgs evArgs) { if (null != uplTheFile.PostedFile) { try { const int BUFFER_SIZE = 255; int nBytesRead = 0; Byte[] Buffer = new Byte[BUFFER_SIZE]; StringBuilder strUploadedContent = new StringBuilder(""); Stream theStream = uplTheFile.PostedFile.InputStream; nBytesRead = theStream.Read(Buffer, 0, BUFFER_SIZE); while (0 != nBytesRead) { strUploadedContent.Append( Encoding.ASCII.GetString(Buffer,0,nBytesRead)); nBytesRead = theStream.Read(Buffer,0,BUFFER_SIZE); } txtOutput.InnerHtml = strUploadedContent.ToString(); } catch (Exception e) { txtOutput.InnerHtml = "Fehler beim Speichern von <b>" + uplTheFile.PostedFile.FileName + "</b><br>"+ e.ToString(); } } } </script> <table> <form enctype="multipart/form-data" runat="server"> <tr> <td>Datei auswählen:</td> <td><input id="uplTheFile" type=file runat="server"></td> </tr> <tr> <td colspan="2"> <input type=button id="btnUploadTheFile" value="Speichern" OnServerClick="btnUploadTheFile_Click" runat="server"> </td> </tr> </form> </table> <span id=txtOutput style="font: 8pt verdana;" runat="server" /> </body> </html>
Der Formularteil des Scripts ist bereits aus dem vorigen Listing bekannt, einzig und allein das Feld für die Namensgebung der Datei am Server fehlt - man braucht es nicht mehr. Was sind nun aber die Änderungen am Code für den Upload selbst? Im Grunde ist es nur dieser Part:
const int BUFFER_SIZE = 255; int nBytesRead = 0; Byte[] Buffer = new Byte[BUFFER_SIZE]; StringBuilder strUploadedContent = new StringBuilder(""); Stream theStream = uplTheFile.PostedFile.InputStream; nBytesRead = theStream.Read(Buffer, 0, BUFFER_SIZE); while (0 != nBytesRead) { strUploadedContent.Append( Encoding.ASCII.GetString(Buffer,0,nBytesRead)); nBytesRead = theStream.Read(Buffer,0,BUFFER_SIZE); }
Zuerst definiere ich eine Konstante, und instanziere darauffolgend drei Variablen, die in der Bearbeitung der Streamdaten benötigt werden: eine Variable, die die Anzahl der gelesenen Bytes speichert, der Puffer für die gelesenen Daten, und der StringBuilder, der dazu verwendet wird, um die auf ASCII konvertierten eingelesenen Streamdaten zu speichern.
Und dann beginnt die Action - zuerst hole ich mir eine Referenz auf den Stream, der über das Object HttpPostedFile zur Verfügung gestellt wird (dieses wiederum über die Eigenschaft PostedFile des HtmlInputFile Objects). Dadurch erspare ich mir weitere Zugriffe auf Eigenschaften und fremde Objekte, die nur die Rechenzeit verlängern würden.
Dann lese ich die ersten Daten ein, und steige damit in die while Schleife ein. Dort wird der Puffer auf ASCII konvertiert, und die nächsten Daten eingelesen. Die while Schleife wird dann abgebrochen, wenn keine Daten mehr am Server angekommen sind.
Ist die while Schleife beendet, habe ich die Daten als String zur Weiterverarbeitung in der Hand - anstatt sie zurück an den Client zu schicken, könnte ich auch den String parsen - oder in eine Datenbank schreiben. Der Anwendungsfall bestimmt die Weiterverwendung.
Übrigens: wenn man die unmodifizierten Binärdaten verwenden möchte, dann sollte man die Konvertierung auf ASCII unterlassen, und je nach Bedarf den richtigen "Zwischenspeicher" verwenden - ein großes Bytearray, einen MemoryStream oder eigene Datenstrukturen.
In diesem Artikel habe ich Ihnen zwei Methoden des Dateiuploads vorgestellt: das Speichern der upgeloadeten Datei am Server mit Hilfe der SaveAs Methode, als auch das direkte Auslesen der Daten mit Hilfe des Stream Objekts. Die letztere Methode wird dann zum Einsatz kommen, wenn man direkt mit den Daten der Datei weiterarbeiten möchte, ohne vorher den Umweg über eine physikalische Datei am Server zu gehen.
This printed page brought to you by AlphaSierraPapa
Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20000802.zip
Beliebige Anzahl von Dateien uploaden
http:/www.aspheute.com/artikel/20010510.htm
Dateien mit dem Browser auf Webserver laden
http:/www.aspheute.com/artikel/19990812.htm
Dateiupload mit ASP und WSC
http:/www.aspheute.com/artikel/20010202.htm
Dateiupload mit ASP.NET und VB.NET
http:/www.aspheute.com/artikel/20010124.htm
Exception Handling in C#
http:/www.aspheute.com/artikel/20000724.htm
Kontrollstatements in C#
http:/www.aspheute.com/artikel/20000714.htm
On-the-fly Generierung von Graphiken
http:/www.aspheute.com/artikel/20000728.htm
Schleifenbefehle in C#
http:/www.aspheute.com/artikel/20000717.htm
Uploaden einer beliebigen Datei in eine Datenbank
http:/www.aspheute.com/artikel/20001030.htm
Vergleich von DataGrid, DataList und Repeater-Control - was verwende ich wann?
http:/www.aspheute.com/artikel/20040303.htm
Verwendung von Arrays in C#
http:/www.aspheute.com/artikel/20000731.htm
Web-basiertes Dateimanagement mit dem ASP FileMan
http:/www.aspheute.com/artikel/20010507.htm
ASP.NET Download
http://www.dotnetgerman.com/links/dl_aspnet.asp
Die aspDEdotnet Liste
http://www.dotnetgerman.com/listen/aspDEdotnet.asp
©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.