Webmaster, wie ich, die auf Ihrer Web-Site selbstentwickelte Tools zur Verfügung stellen, haben stets das gleiche Problem, wenn sie eine neue Version veröffentlichen wollen: neben der Erstellung des Downloads-Pakets, muss man auch noch den neuen Download über einen angepassten Link in die Seiten einbinden, sofern aus dem Dateinamen ersichtlich werden soll, um welche Version es sich handelt.
Mit etwas Code lässt sich das Deployment solcher Pakete aber auf den reinen FTP-Upload beschränken. Soll sich die Seite doch selbst den aktuellen Download heraussuchen...
In ASP.NET lässt sich das Ganze wunderbar in ein UserControl verpacken, sodaß man beim Entwickeln der Web-Seiten schnell einen neuen Download deklarieren kann, ohne erneut viel Code zu schreiben.
Beginnen wir damit, wie der Download-Link der versionierten Datei aussehen soll. Auf zerbit.de halte ich es so, dass in der ersten Zeile der komplette Name der Datei abgebildet wird und in einer zweiten die Größe der Datei, sowie eine knappe Beschreibung des Pakets.
Beispiel für OutlookSignature:
<a style="font-weight:bold"
href="~/download/outlooksignature1704.zip">outlooksignature1704.zip</a>
<br />85 KB - Programm mit Beispielen
Mit diesen zwei Zeilen erstellen wir ein neues UserControl namens DownloadLink.ascx, das folgendes Markup besitzt:
<%@ Control
Language="VB"
AutoEventWireup="false"
CodeFile="DownloadLink.ascx.vb"
Inherits="controls_DownloadLink" %>
<a style="font-weight:bold"
href="<%=pstcDownloadFile.Path%>"><%=pstcDownloadFile.Caption%></a>
<br /><%=pstcDownloadFile.Size%> - <%=pstcDownloadFile.Remark%>
Anstelle des HREF-Attributs und des Inhaltes des HTML-Links, sowie der zweiten Zeile, ist etwas Inline-Code getreten, der die Werte einer Struktur namens pstcDownloadFile abruft. Diese Structure ist an erster Stelle im Code-Behind deklariert und beinhaltet alle notwendigen Informationen:
Structure DownloadFileStructure
Dim Name As String
Dim Path As String
Dim Caption As String
Dim Size As String
Dim MajorVersion As Integer
Dim MinorVersion As Integer
Dim Release As Integer
Dim Remark As String
End Structure
Public pstcDownloadFile As New DownloadFileStructure
Um die Struktur befüllen zu können muss nun zunächst einmal definiert werden welche Eigenschaften das Control bekommen soll:
| Eigenschaft |
Beschreibung |
Variable im Code |
| DownloadPath |
Pfad zum Download-Ordner aus dem der Download herausgesucht werden soll |
_strDownloadPath |
| FilePattern |
Muster der Download-Datei |
_strFilePattern |
| Caption |
Alternativer Inhalt des Links, wenn nicht der Dateiname verwendet werden soll: |
_strCaption |
| Remark |
Kurze Beschreibung des Pakets |
_strRemark |
Für diese Eigenschaften werden Zugriffsmodifizierer in der Code-Behind-Datei erzeugt, die ich mir hier jetzt mal erspare. Im Download des UserControls weiter unten sind sie natürlich vorhanden.
Das Muster der Download-Datei ist die entscheidende Eigenschaft, denn über sie wird festgelegt nach was im Download-Ordner gesucht werden soll. Da sich die aufeinanderfolgenden Versionspakete in Ihrer Benennung nur durch in der Angabe der Versionsnummer unterscheiden, kann man diese durch einen Platzhalter ersetzen.
So wird zum Beispiel aus:
outlooksignature1704.zip
folgendes Muster:
outlooksignature|xyzz|.zip
Die beiden Pipes begrenzen den auszutauschenden Teil des Dateinamens und die einzelnen Teile der Version werden wie folgt ersetzt:
| Platzhalter |
Beschreibung |
| x |
Major-Version |
| y |
Minor-Version |
| z |
Release/Build |
- Wichtig bei der Benennung der Download-Dateien ist immer das Muster einzuhalten, d.h. ist, wie in diesem Beispiel, das Release zweistellig angegeben, muss bei einem einstelligen Release eine führende Null vorhanden sein.
Mit diesen Informationen ausgestattet, kommen wir nun zur Methode GetActualDownloadFileName, die den aktuellsten Download aus dem angegebenen Order herauspickt und die Struktur pstcDownloadFile befüllt.
Protected Sub GetActualDownloadFileName()
'Pattern splitten und Index des ersten Begrenzers merken
Dim arrPattern() As String = _strFilePattern.Split(New [Char]() {"|"c})
Dim intIndexLeft As Integer = _strFilePattern.IndexOf("|")
'Such-Pattern für FileInfo erstellen
Dim stbSearchPattern As New StringBuilder(arrPattern(1))
stbSearchPattern.Replace("x", "?")
stbSearchPattern.Replace("y", "?")
stbSearchPattern.Replace("z", "?")
Dim strSearchPattern As String = _
arrPattern(0) & stbSearchPattern.ToString & arrPattern(2)
'FileInfo initialisieren und Suche durchführen
Dim objDir As DirectoryInfo = _
New DirectoryInfo(HttpContext.Current.Server.MapPath(_strDownloadPath))
Dim objFiles As FileInfo() = _
objDir.GetFiles(strSearchPattern, SearchOption.TopDirectoryOnly)
'Mit Such-Pattern Vergleichs-Pattern erzeugen
Dim strCompareVersion As String = stbSearchPattern.ToString.Replace("?", "0")
Dim intFoundFile As Integer = 0
Dim strFileVersion As String = ""
'Ergebnis durchlaufen und Dateien anhand des Versionsstrings vergleichen
If objFiles.Length > 0 Then
For i As Integer = 0 To objFiles.Length - 1
'Versionsinformation aus Dateinamen extrahieren
strFileVersion = _
objFiles(i).Name.Substring(intIndexLeft, strCompareVersion.Length)
'Pattern mit String.Comparer lexikalisch vergleichen
If String.Compare(strFileVersion, strCompareVersion) > 0 Then
strCompareVersion = strFileVersion 'Vergleichspattern neu setzen
intFoundFile = i 'Index merken
End If
Next
'Name der Datei in Struktur ablegen
pstcDownloadFile.Name = objFiles(intFoundFile).Name
'Größe der Datei in KiloByte in Struktur ablegen
pstcDownloadFile.Size = _
Format(objFiles(intFoundFile).Length / 1024, "#,##0") & " KB"
'Versionsinformationen ermitteln und in Struktur ablegen
Dim strVersionPattern As String = _
_strFilePattern.Substring(intIndexLeft, strCompareVersion.Length)
Dim intMajorStart As Integer = strVersionPattern.IndexOf("x") - 1
Dim intMinorStart As Integer = strVersionPattern.IndexOf("y") - 1
Dim intReleaseStart As Integer = strVersionPattern.IndexOf("z") - 1
pstcDownloadFile.MajorVersion = strFileVersion.Substring( _
intMajorStart, intMinorStart - intMajorStart)
pstcDownloadFile.MinorVersion = strFileVersion.Substring( _
intMinorStart, intReleaseStart - intMinorStart)
pstcDownloadFile.Release = strFileVersion.Substring( _
intReleaseStart, strCompareVersion.Length - intReleaseStart)
End If
End Sub
Die Methode erzeugt aus dem Muster zunächst ein Such-Pattern, mit dem alle in Frage kommenden Dateien im Download-Ordner ermittelt werden und vergleicht dann alle Treffer lexikalisch, d.h. anhand der extrahierten Version als Text. Das funktioniert, da zum Beispiel der String "1704" einen höheren Wert hat als "1299". Die Fundstelle des höchsten Wertes wird am Ende herangezogen, um die Dateiinformationen zu extrahieren und in der Struktur abzulegen.
Fehlt nur noch die Initialzündung, sprich das Event, das den Stein innerhalb des Controls ins Rollen bringt:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Me.Load
If _strDownloadPath.Length > 0 And _strFilePattern.Length > 0 Then
'Aktuellste Datei ermitteln
Call GetActualDownloadFileName()
'Dateiziel festlegen
pstcDownloadFile.Path = _
ResolveClientUrl(_strDownloadPath) & "/" & pstcDownloadFile.Name
'Inhalt des Link-Elements
If _strCaption.Length > 0 Then
pstcDownloadFile.Caption = _strCaption
Else
pstcDownloadFile.Caption = pstcDownloadFile.Name
End If
'Dateianmerkung festlegen
pstcDownloadFile.Remark = _strRemark
End If
End Sub
Das fertige UserControl kann man nun entweder zentral über die web.config dem Web bekanntmachen...
<add tagPrefix="uct" tagName="DownloadLink"
src="~/MyControls/DownloadLink.ascx" />
oder es lediglich auf den ASPX-Seiten einbinden auf denen es benötigt wird...
<%@ Register TagPrefix="ucx" TagName="DownloadLink"
Src="~/MyControls/DownloadLink.ascx" %>
Die Deklaration innerhalb einer ASPX-Seite sieht dann zum Beispiel so aus:
<uct:DownloadLink ID="lnkOutlookSignature" runat="server"
DownloadPath="~/download"
FilePattern="outlooksignature|xyzz|.zip"
Remark="Programm mit Beispielen" />
In meinem Beispiel verwende ich im Markup des Controls nicht alle Werte, die die Struktur zur Verfügung stellt und in der entsprechenden ASPX-Seite auch nicht alle Eigenschaften, aber jeder der dieses UserControl einsetzen möchte, kann sich seinen Download-Link nach eigenem Gusto anpassen.
In Zukunft ist das Deployen einer neuen Version eines Downloads mit einem FTP-Upload getan. Den Rest erledigt ASP.NET.
zum Download...