ABCPdf.net – Cache Problem gelöst!
Zur Erzeugung von dynamischen PDFs aus unseren Applikationen setzen wir die WebSupergoo Komponente ABCPdf.net 6.0 ein. Das Teil erfüllt bislang die meisten unserer Anforderungen ganz gut, nur mit dem Cache hatten wir schon öfters so unsere Probleme. Der Cache kann zwar disabled werden, das hilft aber nur bedingt weiter.
Folgende Situation: ein Button feuert einen Event und löst eine Methode aus, welche ein neues MemoryStream Objekt erzeugt. ABCPdf.AddImageUrl(url) schreibt nun den Inhalt einer Url direkt in den MemoryStream, dieser wird nun über einen Buffer mit Response.BinaryWrite direkt an den Browser geschickt als downloadbares PDF. Um einen eindeutigen Request zu erstellen (Caching Workaround #1) wird an den übergebenen Url Parameter eine guid (globally unique identifier) angehängt. Anstelle von beispielsweise „http://dotlab.wordpress.com“ lautet der Request nun „http://dotlab.wordpress.com/?guid=95e23081-ee88-464c-8a9c-d6553964793d“. Das hat bis gestern ausgezeichnet funktioniert, als sich aber einige Bildobjekte auf der Ziel-Url veränderten, hat ABCPdf.net die Veränderung nicht bemerkt und weiterhin Bilder aus einem Cache in das PDF geschrieben.
Die Lösung war sehr simpel: auf der Ziel-Url werden die dynamisch geladenen Bilder nun ebenfalls mit einer guid als Parameter geladen. Beispiel:
myImage.ImageUrl = "Image1.jpg?guid=95e23081-ee88-464c-8a9c-d6553964793d";
Das scheint dann auch ABCPdf davon zu überzeugen, dass neue Daten gerendert werden wollen
Fortune Cookie Codes mit .net
Für einen Kunden sollten wir einen Glückscode-Generator schreiben. Die Anforderungen waren relativ simpel: Codes im Format xxxx-xxxx-xxxx, natürlich absolut unique Codes, performant auch bei der Erzeugung von mehreren 100′000 Codes im Zusammenspiel mit einer MS SQL Datenbank.Zur Erzeugung der Codes verwendeten wir die .net GUID (globally unique identifier) Funktion, die diese Arbeit recht hübsch erledigt. In einer For-Next Schlaufe werden die Codes generiert, transformiert und in eine Datatable geschrieben. Die Funktion DeleteDuplicates erstellt einen DataView, sortiert diesen nach Codes und arbeitet sich top-down. Sind zwei aufeinanderfolgende Codes identisch, wird der aktuelle gelöscht. Fertig ist die Geschichte, das Ganze wird in diesem Beispiel in ein XML File gespeichert.Werden die Codes in eine SQL Db gespeichert, kann die Einzigartigkeit zusätzlich überprüft werden mit einer DISTINCT Abfrage.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click ‘number of codes to generate Dim EndCount As Integer = 5000 ‘create the datatable and add a row objDT = New System.Data.DataTable(”CodeTable”) objDT.Columns.Add(”Code”, GetType(String)) ‘create random id, transform code Dim count As Integer For count = 0 To EndCount - 1 ‘edit the string Dim myCode As String = Guid.NewGuid.ToString ‘add some separators and cut the string down on 15 chars (3 x 4chars + 3x 1 separator) myCode = UCase(myCode.Replace(”-”, “”)) myCode = myCode.Insert(4, “-”) myCode = myCode.Insert(9, “-”) myCode = myCode.Substring(0, 14) ‘add to datatable objDR = objDT.NewRow objDR(”Code”) = myCode.ToString objDT.Rows.Add(objDR) Next ’start the sub DeleteDuplicates(objDT) ‘Serialize the datatable object into a xml file objDT.WriteXml(”final_codes.xml”) objDT.WriteXmlSchema(”final_scheme.xslt”) ‘output the number of generated codes lblNumRows.Text = objDT.Rows.Count & ” Codes generiert” End Sub ‘Selects duplicate entries and removes them Public Sub DeleteDuplicates(ByVal dt As DataTable) Dim myDataView As New DataView(dt) myDataView.Sort = “Code” For x As Integer = 0 To myDataView.Count - 2 Dim myDataRowView As DataRowView = myDataView.Item(x) Dim myDataRowViewNext As DataRowView = myDataView.Item(x + 1) If myDataRowView.Item(”Code”).ToString = myDataRowViewNext.Item(”Code”).ToString Then myDataRowView.Delete() End If Next End Sub End Class