Text/Tao Gang
Der Umgang mit großen Dateidownloads in Webanwendungen war schon immer bekanntermaßen schwierig, so dass der Benutzer bei den meisten Websites traurig ist, wenn der Download unterbrochen wird. Aber das müssen wir jetzt nicht tun, denn Sie können Ihre ASP.NET-Anwendung in die Lage versetzen, wiederaufnehmbare (kontinuierliche) Downloads großer Dateien zu unterstützen. Mit der in diesem Artikel bereitgestellten Methode können Sie den Download-Prozess verfolgen, sodass Sie dynamisch erstellte Dateien verarbeiten können – und dies ohne die Notwendigkeit von ISAPI-Dynamic-Link-Bibliotheken und nicht verwaltetem C++-Code.
Es ist am einfachsten, Kunden einen Service zum Herunterladen von Dateien aus dem Internet anzubieten, oder? Kopieren Sie einfach die herunterladbare Datei in Ihr Webanwendungsverzeichnis, veröffentlichen Sie den Link und lassen Sie IIS alle damit verbundenen Arbeiten erledigen. Allerdings sollte die Dateibereitstellung nicht mehr als eine Nervensäge sein, Sie möchten nicht, dass die ganze Welt Zugriff auf Ihre Daten hat, Sie möchten nicht, dass Ihr Server mit Hunderten von statischen Dateien verstopft ist, Sie möchten nicht, dass Sie möchten nicht einmal temporäre Dateien herunterladen – diese Dateien werden nur während der Leerlaufzeit erstellt, nachdem der Client mit dem Herunterladen begonnen hat.
Leider ist es nicht möglich, diese Effekte mit der Standardantwort von IIS auf Download-Anfragen zu erzielen. Um also die Kontrolle über den Download-Prozess zu erlangen, müssen Entwickler im Allgemeinen einen Link zu einer benutzerdefinierten ASPX-Seite erstellen, auf der sie die Anmeldeinformationen des Benutzers überprüfen, eine herunterladbare Datei erstellen und den folgenden Code verwenden, um die Datei an den Client zu übertragen:
Response.WriteFile
Response.End()
Und hier entsteht das eigentliche Problem.
Was ist das Problem?
Die WriteFile-Methode sieht perfekt aus, sie sorgt dafür, dass die Binärdaten der Datei an den Client fließen. Was wir jedoch bis vor kurzem nicht wussten, ist, dass die WriteFile-Methode ein berüchtigter Speicherfresser ist, der die gesamte Datei zur Bereitstellung in den RAM des Servers lädt (tatsächlich nimmt sie die doppelte Größe der Datei ein). Bei großen Dateien kann dies zu Dienstspeicherproblemen und möglicherweise zu doppelten ASP.NET-Prozessen führen. Doch im Juni 2004 veröffentlichte Microsoft einen Patch, der das Problem löste. Dieser Patch ist jetzt Teil des .NET Framework 1.1 Service Pack (SP1).
Mit diesem Patch wird die TransmitFile-Methode eingeführt, die eine Festplattendatei in einen kleineren Speicherpuffer liest und dann mit der Übertragung der Datei beginnt. Obwohl diese Lösung die Speicher- und Schleifenprobleme löst, ist sie immer noch unbefriedigend. Sie haben keine Kontrolle über den Antwortlebenszyklus. Sie können nicht wissen, ob der Download korrekt abgeschlossen wurde, Sie können nicht wissen, ob der Download unterbrochen wurde, und (wenn Sie temporäre Dateien erstellt haben) Sie können nicht wissen, ob und wann Sie die Dateien löschen sollten. Schlimmer noch: Wenn der Download fehlschlägt, beginnt die TransmitFile-Methode mit dem Herunterladen vom Anfang der Datei, die der Client als nächstes versucht.
Eine mögliche Lösung, die Implementierung eines Background Intelligent Transfer Service (BITS), ist für die meisten Websites nicht realisierbar, da dadurch der Zweck der Aufrechterhaltung der Unabhängigkeit von Client-Browser und Betriebssystem zunichte gemacht würde.
Die Grundlage für eine zufriedenstellende Lösung ist der erste Versuch von Microsoft, das durch WriteFile verursachte Speicherverwirrungsproblem zu lösen (siehe Knowledge Base-Artikel 812406). In diesem Artikel wurde ein intelligenter Prozess zum Herunterladen von Chunk-Daten demonstriert, der Daten aus einem Dateistream liest. Bevor der Server den Byteblock an den Client sendet, prüft er anhand der Eigenschaft „Response.IsClientConnected“, ob der Client noch verbunden ist. Wenn die Verbindung noch offen ist, sendet sie weiterhin Stream-Bytes, andernfalls stoppt sie, um zu verhindern, dass der Server unnötige Daten sendet.
Dies ist die Vorgehensweise, die wir insbesondere beim Herunterladen temporärer Dateien verfolgen. Wenn IsClientConnected „False“ zurückgibt, wissen Sie, dass der Downloadvorgang unterbrochen wurde und Sie die Datei speichern sollten. Andernfalls löschen Sie die temporäre Datei, wenn der Vorgang erfolgreich abgeschlossen wird. Um einen unterbrochenen Download fortzusetzen, müssen Sie außerdem lediglich den Download an der Stelle starten, an der die Client-Verbindung beim letzten Download-Versuch fehlgeschlagen ist.
Unterstützung für HTTP-Protokoll und Header-Informationen (Header) Mithilfe der
HTTP-Protokollunterstützung können Header-Informationen für unterbrochene Downloads verarbeitet werden. Durch die Verwendung einer kleinen Anzahl von HTTP-Headern können Sie Ihren Download-Prozess so verbessern, dass er vollständig der HTTP-Protokollspezifikation entspricht. Diese Spezifikation stellt zusammen mit den Bereichen alle Informationen bereit, die zum Fortsetzen eines unterbrochenen Downloads erforderlich sind.
So funktioniert es. Wenn der Server clientseitige fortsetzbare Downloads unterstützt, sendet er zunächst den Accept-Ranges-Header in der ersten Antwort. Der Server sendet außerdem einen Entity-Tag-Header (ETag), der eine eindeutige Identifizierungszeichenfolge enthält.
Der folgende Code zeigt einige der Header, die IIS als Reaktion auf eine erste Download-Anfrage an den Client sendet, die die Details der angeforderten Datei an den Client übergibt.
HTTP/1.1 200 OK
Verbindung: schließen
Datum: Di, 19. Okt. 2004 15:11:23 GMT
Akzeptanzbereiche: Bytes
Zuletzt geändert: So, 26. September 2004 15:52:45 GMT
ETag: „47febb2cfd76c41:2062“
Cache-Kontrolle: privat
Inhaltstyp: application/x-zip-komprimiert
Inhaltslänge: 2844011
Nach dem Empfang dieser Header-Informationen sendet der IE-Browser bei einer Unterbrechung des Downloads in nachfolgenden Download-Anfragen den Etag-Wert und die Range-Header-Informationen an den Server zurück. Der folgende Code zeigt einige der Header, die der IE an den Server sendet, wenn er versucht, einen unterbrochenen Download fortzusetzen.
GET
Diese Header zeigen an, dass der IE das von IIS bereitgestellte Entitäts-Tag zwischengespeichert und im If-Range-Header an den Server zurückgesendet hat. Auf diese Weise kann sichergestellt werden, dass der Download von genau derselben Datei aus fortgesetzt wird. Leider funktionieren nicht alle Browser gleich. Andere vom Client zur Überprüfung der Datei gesendete HTTP-Header können „If-Match“, „If-Unmodified-Since“ oder „Unless-Modified-Since“ lauten. Offensichtlich ist in der Spezifikation nicht explizit angegeben, welche Header die Client-Software unterstützen oder welche Header verwendet werden müssen. Daher verwenden einige Clients überhaupt keine Header-Informationen, während IE nur If-Range und Unless-Modified-Since verwendet. Überprüfen Sie diese Informationen besser mit Code. Wenn Sie diesen Ansatz wählen, kann Ihre Anwendung die HTTP-Spezifikation auf einem sehr hohen Niveau einhalten und mit einer Vielzahl von Browsern funktionieren. Der Range-Header gibt den angeforderten Bytebereich an – in diesem Fall ist es der Startpunkt, von dem aus der Server den Dateistream fortsetzen soll.
Wenn IIS eine Anforderung vom Typ „Lebenslauf-Download“ empfängt, sendet es eine Antwort zurück, die die folgenden Header-Informationen enthält:
HTTP/1.1 206 Teilinhalt
Inhaltsbereich: Bytes 822603-2844010/2844011
Akzeptanzbereiche: Bytes
Zuletzt geändert: So, 26. September 2004 15:52:45 GMT
ETag: „47febb2cfd76c41:2062“
Cache-Kontrolle: privat
Inhaltstyp: application/x-zip-komprimiert
Inhaltslänge: 2021408
Bitte beachten Sie, dass der obige Code eine etwas andere HTTP-Antwort als die ursprüngliche Download-Anfrage hat – die Anfrage zum Fortsetzen des Downloads lautet 206, während die ursprüngliche Download-Anfrage 200 war. Dies weist darauf hin, dass es sich bei der über die Leitung übertragenen Datei um eine Teildatei handelt. Diesmal gibt der Content-Range-Header die genaue Anzahl und Position der übergebenen Bytes an.
Der IE ist bei diesen Header-Informationen sehr wählerisch. Wenn die erste Antwort keine Etag-Header-Informationen enthält, wird IE niemals versuchen, den Download fortzusetzen. Andere von mir getestete Clients verwenden den ETag-Header nicht, sondern verlassen sich einfach auf den Dateinamen und den Anforderungsbereich und verwenden den Last-Modified-Header, wenn sie versuchen, die Datei zu validieren.
Ein umfassendes Verständnis des HTTP-Protokolls.
Die im vorherigen Abschnitt gezeigten Header-Informationen reichen aus, damit die Lösung zum Wiederaufnehmen von Downloads funktioniert, sie decken jedoch nicht vollständig die HTTP-Spezifikation ab.
Der Range-Header kann mehrere Bereiche in einer einzigen Anfrage anfordern, eine Funktion namens „Multipart Ranges“. Nicht zu verwechseln mit segmentiertem Herunterladen, denn fast alle Download-Tools nutzen segmentiertes Herunterladen, um die Download-Geschwindigkeit zu erhöhen. Diese Tools behaupten, die Download-Geschwindigkeit zu erhöhen, indem sie zwei oder mehr gleichzeitige Verbindungen öffnen, von denen jede einen anderen Dateibereich anfordert.
Die Idee mehrteiliger Bereiche öffnet nicht mehrere Verbindungen, sondern ermöglicht der Client-Software, die ersten zehn und letzten zehn Bytes einer Datei in einem einzigen Anfrage-/Antwortzyklus anzufordern.
Ehrlich gesagt habe ich noch nie eine Software gefunden, die diese Funktion nutzt. Aber ich weigere mich, in die Codedeklaration zu schreiben: „Es ist nicht vollständig HTTP-kompatibel“. Das Weglassen dieser Funktion verstößt definitiv gegen Murphys Gesetz. Unabhängig davon werden bei E-Mail-Übertragungen mehrteilige Bereiche verwendet, um Header-Informationen, Klartext und Anhänge zu trennen.
Beispielcode
Wir wissen, wie Client und Server Header-Informationen austauschen, um fortsetzbare Downloads sicherzustellen. Durch die Kombination dieses Wissens mit der Idee des Dateiblock-Streamings können Sie Ihren ASP.NET-Anwendungen zuverlässige Download-Verwaltungsfunktionen hinzufügen.
Die Möglichkeit, die Kontrolle über den Download-Prozess zu erlangen, besteht darin, die Download-Anfrage vom Client abzufangen, die Header-Informationen zu lesen und entsprechend zu reagieren. Vor .NET mussten Sie eine ISAPI-Anwendung (Internet Server API) schreiben, um diese Funktionalität zu implementieren. Die .NET Framework-Komponente stellt jedoch eine IHttpHandler-Schnittstelle bereit, die es Ihnen bei Implementierung in einer Klasse ermöglicht, dies nur mit .NET-Code Intercept zu tun und Bearbeitung von Anfragen. Dies bedeutet, dass Ihre Anwendung die volle Kontrolle und Reaktionsfähigkeit über den Download-Prozess hat und niemals automatisierte IIS-Funktionen einbezieht oder verwendet.
Der Beispielcode enthält eine benutzerdefinierte HttpHandler-Klasse (ZIPHandler) in der Datei HttpHandler.vb. ZipHandler implementiert die IhttpHandler-Schnittstelle und verarbeitet Anforderungen für alle ZIP-Dateien.
Um den Beispielcode zu testen, müssen Sie ein neues virtuelles Verzeichnis in IIS erstellen und die Quelldateien dorthin kopieren. Erstellen Sie in diesem Verzeichnis eine Datei mit dem Namen download.zip (bitte beachten Sie, dass IIS und ASP.NET keine Downloads verarbeiten können, die größer als 2 GB sind. Stellen Sie daher sicher, dass Ihre Datei diese Grenze nicht überschreitet). Konfigurieren Sie Ihr virtuelles IIS-Verzeichnis so, dass die Erweiterung .zip über aspnet_isapi.dll zugeordnet wird.
HttpHandler-Klasse: Nachdem ZIPHandler
die .zip-Erweiterung in ASP.NET zugeordnet hat, ruft IIS jedes Mal, wenn der Client eine .zip-Datei vom Server anfordert, die ProcessRequest-Methode der ZipHandler-Klasse auf (siehe Download-Code).
Die ProcessRequest-Methode erstellt zunächst eine Instanz der benutzerdefinierten FileInformation-Klasse (siehe Download-Code), die den Status des Downloads kapselt (z. B. in Bearbeitung, unterbrochen usw.). Das Beispiel kodiert den Pfad zur Beispieldatei „download.zip“ fest in den Code. Wenn Sie diesen Code auf Ihre eigene Anwendung anwenden, müssen Sie ihn ändern, um die angeforderte Datei zu öffnen.
' Verwenden Sie objRequest, um zu erkennen, welche Datei angefordert wurde, und verwenden Sie die Datei, um objFile zu öffnen.
' Zum Beispiel objFile = New Download.FileInformation(<vollständiger Dateiname>)
objFile = New Download.FileInformation( _
objContext.Server.MapPath("~/download.zip"))
Als nächstes führt das Programm die Anfrage unter Verwendung der beschriebenen HTTP-Header aus (sofern die Header in der Anfrage zum ersten Mal unter der Sonne bereitgestellt wurden). Wenn eine Validierungsprüfung fehlschlägt, wird die Antwort sofort beendet und der entsprechende StatusCode-Wert gesendet.
Wenn nicht objRequest.HttpMethod.Equals(HTTP_METHOD_GET) oder nicht
objRequest.HttpMethod.Equals(HTTP_METHOD_HEAD) Dann
' Derzeit werden nur GET- und HEAD-Methoden unterstützt. objResponse.StatusCode = 501 ' Nicht ausgeführt
ElseIf Not objFile.Exists Then
' Die angeforderte Datei konnte nicht gefunden werden objResponse.StatusCode = 404 ' Nicht gefunden
ElseIf objFile.Length > Int32.MaxValue Then
'Die Datei ist zu groß. objResponse.StatusCode = 413 'Die Anforderungsentität ist zu groß
ElseIf Not ParseRequestHeaderRange(objRequest, alRequestedRangesBegin, alRequestedRangesend, _
objFile.Length, bIsRangeRequest) Dann
' Die Range-Anfrage enthält nutzlose Entitäten. objResponse.StatusCode = 400 ' Nutzlose Anfrage
ElseIf Not CheckIfModifiedSince(objRequest,objFile) Then
'Die Entität wurde nicht geändert. objResponse.StatusCode = 304 'Die Entität wurde nicht geändert
ElseIf Not CheckIfUnmodifiedSince(objRequest,objFile) Then
' Die Entität wurde seit dem letzten angeforderten Datum geändert. objResponse.StatusCode = 412 ' Vorverarbeitung fehlgeschlagen
ElseIf Not CheckIfMatch(objRequest, objFile) Then
' Die Entität stimmt nicht mit der Anfrage überein. objResponse.StatusCode = 412 ' Vorverarbeitung fehlgeschlagen
ElseIf Not CheckIfNoneMatch(objRequest, objResponse,objFile) Then
' Die Entität stimmt mit der Nichtübereinstimmungsanforderung überein.
'Der Antwortcode befindet sich in der CheckIfNoneMatch-Funktion
Anders
'Vorprüfung erfolgreich
Die ParseRequestHeaderRange-Funktion prüft in diesen Vorprüfungen (siehe Download-Code), ob der Client einen Dateibereich angefordert hat (was einen teilweisen Download bedeutet). Wenn der angeforderte Bereich ungültig ist (ein ungültiger Bereich ist ein Bereichswert, der die Dateigröße überschreitet oder eine unangemessene Zahl enthält), setzt diese Methode bIsRangeRequest auf True. Wenn ein Bereich angefordert wird, überprüft die CheckIfRange-Methode die IfRange-Headerinformationen.
Wenn der angeforderte Bereich gültig ist, berechnet der Code die Größe der Antwortnachricht. Wenn der Client mehrere Bereiche angefordert hat, enthält der Wert für die Antwortgröße den Wert für die Länge des mehrteiligen Headers.
Wenn ein gesendeter Header-Wert nicht ermittelt werden kann, behandelt das Programm die Download-Anfrage als erste Anfrage und nicht als Teil-Download und sendet einen neuen Download-Stream, beginnend am Anfang der Datei.
If bIsRangeRequest AndAlso CheckIfRange(objRequest, objFile) Then
„Dies ist eine Bereichsanforderung“ Wenn das Range-Array mehrere Entitäten enthält, handelt es sich auch um eine mehrteilige Bereichsanforderung bMultipart = CBool(alRequestedRangesBegin.GetUpperBound(0)>0)
' Gehen Sie in jeden Bereich, um die gesamte Antwortlänge zu erhalten. For iLoop = alRequestedRangesBegin.GetLowerBound(0) To alRequestedRangesBegin.GetUpperBound(0)
'Die Länge des Inhalts (in diesem Bereich)
iResponseContentLength += Convert.ToInt32(alRequestedRangesend( _
iLoop) – alRequestedRangesBegin(iLoop)) + 1
Wenn bMultipart Dann
' Wenn es sich um eine mehrteilige Bereichsanforderung handelt, berechnen Sie die Länge der zu sendenden Zwischenheaderinformationen iResponseContentLength += MULTIPART_BOUNDARY.Length
iResponseContentLength += objFile.ContentType.Length
iResponseContentLength += alRequestedRangesBegin(iLoop).ToString.Length
iResponseContentLength += alRequestedRangesend(iLoop).ToString.Length
iResponseContentLength += objFile.Length.ToString.Length
' 49 ist die Länge von Zeilenumbrüchen und anderen notwendigen Zeichen in mehrteiligen Downloads iResponseContentLength += 49
Ende wenn
Nächster iLoop
Wenn bMultipart Dann
' Wenn es sich um eine mehrteilige Bereichsanforderung handelt,
' Wir müssen auch die Länge des letzten Zwischenheaders berechnen, der gesendet wird: iResponseContentLength +=MULTIPART_BOUNDARY.Length
' 8 ist die Länge des Bindestrichs und des Zeilenumbruchs iResponseContentLength += 8
Anders
' Kein mehrteiliger Download, daher müssen wir den Antwortbereich des anfänglichen HTTP-Headers angeben objResponse.AppendHeader( HTTP_HEADER_CONTENT_RANGE, "bytes " & _
alRequestedRangesBegin(0).ToString & "-" & _
alRequestedRangesend(0).ToString & "/" & _
objFile.Length.ToString)
'Ende wenn
' Bereichsantwort objResponse.StatusCode = 206 ' Teilantwort Sonst
„Dies ist keine Bereichsanforderung, oder die angeforderte Bereichsentitäts-ID stimmt nicht mit der aktuellen Entitäts-ID überein.
„Also einen neuen Download starten“ gibt an, dass die Größe des abgeschlossenen Teils der Datei der Länge des Inhalts entspricht. iResponseContentLength =Convert.ToInt32(objFile.Length)
'Zurück zum normalen OK-Status objResponse.StatusCode = 200
Ende wenn
' Als nächstes muss der Server mehrere wichtige Antwortheader senden, z. B. Inhaltslänge, Etag und Dateiinhaltstyp:
' Schreiben Sie die Inhaltslänge in die Antwort objResponse.AppendHeader( HTTP_HEADER_CONTENT_LENGTH,iResponseContentLength.ToString)
' Schreiben Sie das Datum der letzten Änderung in die Antwort objResponse.AppendHeader( HTTP_HEADER_LAST_MODIFIED,objFile.LastWriteTimeUTC.ToString("r"))
' Teilen Sie der Client-Software mit, dass wir die Bereichsanforderung akzeptiert haben. objResponse.AppendHeader( HTTP_HEADER_ACCEPT_RANGES,HTTP_HEADER_ACCEPT_RANGES_BYTES)
' Schreiben Sie das Entity-Tag der Datei in die Antwort (in Anführungszeichen eingeschlossen).
objResponse.AppendHeader(HTTP_HEADER_ENTITY_TAG, „““ & objFile.EntityTag & „““)
'Inhaltstyp in „responseIf bMultipart Then“ schreiben
„Mehrteilige Nachrichten haben diesen speziellen Typ“ Im Beispiel wird der tatsächliche MIME-Typ der Datei später in die Antwort geschrieben objResponse.ContentType = MULTIPART_CONTENTTYPE
Anders
'Der Dateiinhaltstyp, der einer einzelnen Teilnachricht gehört. objResponse.ContentType = objFile.ContentType
Ende wenn
Alles, was Sie zum Herunterladen benötigen, ist bereit und Sie können mit dem Herunterladen der Dateien beginnen. Sie verwenden ein FileStream-Objekt, um Byteblöcke aus einer Datei zu lesen. Legen Sie die State-Eigenschaft der FileInformation-Instanz objFile auf fsDownloadInProgress fest. Solange der Client verbunden bleibt, liest der Server Byteblöcke aus der Datei und sendet sie an den Client. Bei mehrteiligen Downloads sendet dieser Code spezifische Header-Informationen. Wenn der Client die Verbindung trennt, setzt der Server den Dateistatus auf „fsDownloadBroken“. Wenn der Server das Senden des angeforderten Bereichs abschließt, setzt er den Status auf fsDownloadFinished (siehe Download-Code).
FileInformation-Hilfsklasse
Im Abschnitt „ZIPHandler“ finden Sie, dass FileInformation eine Hilfsklasse ist, die Informationen zum Download-Status kapselt (z. B. wird heruntergeladen, unterbrochen usw.).
Um eine Instanz von FileInformation zu erstellen, müssen Sie den Pfad zur angeforderten Datei an den Konstruktor der Klasse übergeben:
Public Sub New(ByVal sPath As String)
m_objFile = Neues System.IO.FileInfo(sPath)
End Sub
FileInformation verwendet das System.IO.FileInfo-Objekt, um Dateiinformationen abzurufen, die als Eigenschaften des Objekts angezeigt werden (z. B. ob die Datei vorhanden ist, der vollständige Name der Datei, Größe usw.). Diese Klasse stellt auch eine DownloadState-Enumeration bereit, die die verschiedenen Zustände der Download-Anfrage beschreibt:
Enum DownloadState
' Clear: Kein Download-Prozess, die Datei behält möglicherweise fsClear = 1 bei
'Gesperrt: Dynamisch erstellte Dateien können nicht geändert werden fsLocked = 2
„In Bearbeitung: Die Datei ist gesperrt und der Downloadvorgang läuft fsDownloadInProgress = 6
„Broken: Die Datei ist gesperrt, der Download-Vorgang war im Gange, wurde aber abgebrochen fsDownloadBroken = 10
' Fertig: Die Datei ist gesperrt und der Downloadvorgang ist abgeschlossen fsDownloadFinished = 18
End Enum
FileInformation stellt auch den EntityTag-Attributwert bereit. Dieser Wert ist im Beispielcode fest codiert, da der Beispielcode nur eine Downloaddatei verwendet und diese Datei nicht geändert wird. Für eine echte Anwendung stellen Sie jedoch mehrere Dateien bereit, auch dynamisch. Um Dateien zu erstellen, muss Ihr Code eine bereitstellen eindeutiger EntityTag-Wert für jede Datei. Darüber hinaus muss sich dieser Wert jedes Mal ändern, wenn die Datei geändert oder modifiziert wird. Dadurch kann die Client-Software überprüfen, ob die heruntergeladenen Byte-Blöcke noch aktuell sind. Hier ist der Teil des Beispielcodes, der den hartcodierten EntityTag-Wert zurückgibt:
Public ReadOnly Property EntityTag() As String
' EntityTag wird für die erste (200) Antwort an den Client und für Wiederherstellungsanforderungen vom Client Get verwendet
' Erstellen Sie eine eindeutige Zeichenfolge für die Datei.
' Beachten Sie, dass der eindeutige Code beibehalten werden muss, solange sich die Datei nicht ändert.
' Wenn sich die Datei jedoch ändert oder modifiziert wird, muss sich dieser Code ändern.
Rückgabe „MyExampleFileID“
Beenden Sie Get
End-Eigenschaft
Ein einfaches und im Allgemeinen sicheres EntityTag könnte aus dem Dateinamen und dem Datum der letzten Änderung der Datei bestehen. Unabhängig davon, welche Methode Sie verwenden, müssen Sie sicherstellen, dass dieser Wert wirklich eindeutig ist und nicht mit dem EntityTag anderer Dateien verwechselt werden kann. Ich möchte die erstellten Dateien in meiner Anwendung dynamisch nach Client, Kunde und Postleitzahlenindex benennen und die als EntityTag verwendete GUID in der Datenbank speichern.
Die ZipFileHandler-Klasse liest und legt die öffentliche State-Eigenschaft fest. Nach Abschluss des Downloads wird der Status auf „fsDownloadFinished“ gesetzt. Zu diesem Zeitpunkt können Sie die temporären Dateien löschen. Hier müssen Sie im Allgemeinen die Save-Methode aufrufen, um den Status beizubehalten.
Public Property State() als DownloadState
Erhalten
Gibt m_nState zurück
Beenden Sie Get
Set(ByVal nState As DownloadState)
m_nState = nState
' Optionale Aktion: Sie können die Datei zu diesem Zeitpunkt automatisch löschen.
' Wenn der Status auf „Fertig“ gesetzt ist, benötigen Sie diese Datei nicht mehr.
' Wenn nState =DownloadState.fsDownloadFinished Dann
'Klar()
'Anders
'Speichern()
'Ende wenn
Speichern()
Endsatz
End Property
ZipFileHandler sollte die Save-Methode jedes Mal aufrufen, wenn sich der Dateistatus ändert, um den Dateistatus zu speichern, damit er dem Benutzer später angezeigt werden kann. Sie können damit auch den von Ihnen selbst erstellten EntityTag speichern. Bitte speichern Sie den Dateistatus und den EntityTag-Wert nicht in der Anwendung, Sitzung oder im Cache – Sie müssen die Informationen über den Lebenszyklus aller dieser Objekte hinweg speichern.
PrivateSubSave()
'Speichern Sie den Download-Status der Datei in der Datenbank oder XML-Datei.
' Wenn Sie die Datei nicht dynamisch erstellen, müssen Sie diesen Status natürlich nicht speichern.
End Sub
Wie bereits erwähnt, verarbeitet der Beispielcode nur eine vorhandene Datei (download.zip), Sie können dieses Programm jedoch weiter erweitern, um die angeforderte Datei nach Bedarf zu erstellen.
Beim Testen des Beispielcodes ist Ihr lokales System oder LAN möglicherweise zu schnell, um den Downloadvorgang zu unterbrechen. Daher empfehle ich Ihnen, eine langsame LAN-Verbindung zu verwenden (das Reduzieren der Bandbreite der Site in IIS ist eine Simulationsmethode) oder den Server zu installieren das Internet.
Das Herunterladen von Dateien auf den Client ist immer noch ein Problem. Ein falscher oder falsch konfigurierter Web-Cache-Server, der von einem ISP betrieben wird, kann dazu führen, dass das Herunterladen großer Dateien fehlschlägt, einschließlich schlechter Download-Leistung oder vorzeitiger Sitzungsbeendigung. Wenn die Dateigröße 255 MB überschreitet, sollten Sie Kunden dazu ermutigen, Download-Verwaltungssoftware von Drittanbietern zu verwenden, obwohl einige neuere Browser über integrierte grundlegende Download-Manager verfügen.
Wenn Sie den Beispielcode weiter erweitern möchten, kann es hilfreich sein, die HTTP-Spezifikation zu konsultieren. Sie können MD5-Prüfsummen für Downloads einrichten und diese mithilfe des Content-MD5-Headers hinzufügen, um die Integrität heruntergeladener Dateien zu überprüfen. Der Beispielcode umfasst keine anderen HTTP-Methoden außer GET und HEAD.