CCC-Fahrplan 👍 👎

Pünktlich zum aktuellen Chaos Communication Congress des CCC möchte ich ein kleines Projekt vorstellen.

Meine Variante des CCC-Fahrplans greift auf die XML- und JSON-Dateien des offiziellen Zeitplans zurück, stellt dadurch alle Veranstaltungen (seit 2006) und Sprecher (seit 2013) einheitlich dar und enthält einige Querverweise. Darüber hinaus ermöglichen die Flaggen eine besonders schnelle Sprachzuordnung direkt auf der Startseite.

Zur Schonung der Infrastruktur des CCC werden die Daten zwischengespeichert, sodass die angezeigten Informationen u. U. veraltet sein können. Bitte informiere dich für verbindliche Informationen direkt beim CCC.

Parameter einer Java-Methode per Reflexion ermitteln 👍 👎

Für ein kleines Projekt (mehr dazu in einem separaten Beitrag) war es notwendig, die Parameter von Methoden per Reflexion in Java zu ermitteln. Die entsprechende Funktionalität findet sich im Paket java.lang.reflect.
Parameter einer Java-Methode per Reflexion ermitteln
0102030405060708091011121314151617181920
public static List<Map<String,String>> GetMethodParameterList(    String typeName,    String methodName) throws ClassNotFoundException {    List<Map<String,String>> methodList = new ArrayList<>();
for(Method method : Class.forName(typeName).getMethods()) { if(method.getName().equals(methodName)) { HashMap<String,String> parameterList = new HashMap<>();
for(Parameter parameter : method.getParameters()) { parameterList.put(parameter.getName(), parameter.getType().getCanonicalName()); }
methodList.add(parameterList); } }
return methodList;}
Ähnlich zu LINQ bei C# gibt es für Java sogenannte Streams; wir können obige Implementierung damit beispielsweise wie folgt unter einem funktionalem Paradigma schreiben:
Implementierung mit Java-Streams
010203040506070809101112
public static List<Map<String,String>> GetMethodParameterList(    String typeName,    String methodName) throws ClassNotFoundException {    return Stream.of(Class.forName(typeName).getMethods())        .filter(m -> m.getName().equals(methodName))        .map(m -> Stream.of(m.getParameters()).collect(Collectors.toMap(            k -> k.getName(),            v -> v.getType().getCanonicalName()        )))        .collect(Collectors.toList());}
Die Verwendung gestaltet sich jeweils identisch:
Methode verwenden und Ergebnis auf der Standardausgabe ausgeben
01020304050607
List<Map<String,String>> methodList = GetMethodParameterList(typeName, methodName);
for(Map<String,String> parameterList : methodList) { for(Map.Entry<String,String> parameter : parameterList.entrySet()) { System.out.println(parameter.getValue() + " " + parameter.getKey()); }}
Es gilt schließlich noch eine kleine Besonderheit zu berücksichtigen: Standardmäßig stehen die Bezeichner der Parameter unter Java nicht zur Verfügung, sondern würden schlicht durchnummeriert. Um die tatsächlichen Bezeichner zu erhalten, muss mit der Option -parameters kompiliert werden. Verbreitete Entwicklungsumgebungen wie Eclipse oder NetBeans bieten hierfür entsprechende Einstellungen.

Wir bereits früher angekündigt werde ich zur Reflexion in C# noch einen etwas ausführlicheren Beitrag schreiben und dann dort eine entsprechende Implementierung ähnlicher Funktionalität vorstellen.

Wissen(schaft)spodcasts 👍 👎

In früheren Beiträgen hatte ich bereits ein paar Podcast-Empfehlungen ausgesprochen und auf mein Feedreader-Projekt hingewiesen, welches ebenfalls einige Podcasts aus verschiedenen Themenbereichen bereithält.

Mit diesem Beitrag möchte ich darüber hinaus gerne auf Wissenschaftspodcasts hinweisen. Diese Seite wurde von einigen Podcastern aus dem Bereich der Wissenschafts- und Wissensvermittlung ins Leben gerufen. Zu den Gründern gehören u. a. auch Nicolas Wöhrl von methodisch inkorrekt und Markus Völter von omega tau – beides Podcasts, die ich schon seit sehr langer Zeit verfolge und auch hier bereits beworben habe.

Die von den genannten und weiteren Personen eröffnete Seite bietet nun eine Sammlung verschiedenster Podcasts aus den Bereichen Wissen und Wissenschaft. Das Themenspektrum ist breit abgedeckt und reicht von Archäologie, Geschichte und Technik über Astronomie, Forschung im Allgemeinen und Speziellen bis hin zu Mathematik und Naturwissenschaften. Ich gehe also davon aus, dass für (fast) alle meiner – sicherlich hauptsächlich technisch interessierten – Besucher etwas dabei sein dürfte. Ihr könnt darüber hinaus auch neue Vorschläge einreichen.

Da mir die Vermittlung von Wissen und das Gespräch über wissenschaftliche Erkenntnisse persönlich äußerst wichtige Angelegenheiten sind, würde ich mich sehr freuen, wenn ihr etwas Passendes findet und die Seite(n) weiterempfehlt. Der Vollständigkeit wegen möchte ich abschließend noch kurz darauf hinweisen, dass ich mit den genannten Seiten in keiner weiteren Verbindung außer als Zuhörer einiger Podcasts stehe.

Hintergrundaufgaben unter ASP.NET ausführen 👍 👎

Im Vergleich zu manch anderen Laufzeitumgebungen für Web-Anwendungen ist es bei ASP.NET auch hier recht einfach, Aufgaben im Hintergrund (beispielsweise über separate Threads) auszuführen. Obwohl das grundsätzlich jederzeit sehr einfach – abgesehen von den inhärenten Schwierigkeiten, die Nebenläufigkeit mit sich bringen kann – möglich ist, ist das einfache Vorgehen, wie man es aus dem Desktop-Bereich kennt, fehleranfällig.

Im einfachsten Fall würde man asynchron per Task.Run(…) (als mit häufig genutzten Standardwerten vorbelegte Abkürzung für Task.Factory.StartNew(…)) zur Verwendung des Standard-Thread-Pools oder manuell per Thread-Klasse arbeiten. Dies ist jedoch insofern problematisch, als dass die ASP.NET-Anwendungsdomäne davon nicht benachrichtigt wird und daher beispielsweise einerseits auf die Beendigung des Vorgangs nicht gewartet und andererseits auf das Herunterfahren des Arbeitsprozesses nicht reagiert werden kann.

Bereits seit längerer Zeit werden daher u. a. die beiden Methoden RegisterObject und UnregisterObject der HostingEnvironment-Klasse zur Verfügung gestellt, deren Verwendung jedoch etwas umständlich ist und auf Grund neuerer Möglichkeiten, die gleich im Anschluss vorgestellt werden, an dieser Stelle nicht weiter ausgeführt werden soll. Wir verwenden stattdessen die seit .NET 4.5.2 verfügbare QueueBackgroundWorkItem-Methode:
Hintergrundaufgabe hinzufügen
010203
HostingEnvironment.QueueBackgroundWorkItem(cT => {    /* Implementierung der Aufgabe */});
Etwas ungeschickt ist es jedoch, wenn dies beispielsweise in einem separaten Projekt ausgelagert werden soll, um jeweils von einer Desktop- und Web-Anwendung darauf zuzugreifen – außerhalb der ASP.NET-Laufzeitumgebung ist die Verwendung dieser Methode nämlich nicht möglich. Daher stellen wir für diesen Fall eine Alternative zur Verfügung, um zumindest ähnliches Verhalten für alle Anwendungsfälle zur Verfügung zu stellen:
Hilfsmethode (inkl. Fallback) implementieren
010203040506070809101112
public static class TaskUtility {    public static void DoBackgroundWork(        Action<CancellationToken> action,        CancellationToken cancellationToken = default(CancellationToken)    ) {        if(HostingEnvironment.IsHosted) {            HostingEnvironment.QueueBackgroundWorkItem(action);        } else {            Task.Run(() => action(cancellationToken), cancellationToken);        }    }}
Hilfsmethode verwenden
010203
TaskUtility.DoBackgroundWork(cT => {    /* Implementierung der Aufgabe */});
Alternativ wäre es natürlich auch möglich, nur die eigentliche Aufgabe auszulagern und dann anwendungsspezifisch zu starten. Weiterführende Informationen zur Verwendung des CancellationToken stellt das MSDN insbesondere über die Struktur CancellationToken und die Klasse CancellationTokenSource zur Verfügung.

ZIP-Archive mit C# (ent-)packen 👍 👎

In einem früheren Beitrag zur (De-)Kompression mit C# hatte ich bereits einen Beitrag zu ZIP-Archiven in Aussicht gestellt. Diese sind praktisch, um Dateien und Verzeichnisstrukturen komprimiert und zusammenhängend speichern und austauschen zu können und werden außerdem auf praktisch jeder Plattform unterstützt. Daher möchte ich mit diesem Beitrag zeigen, wie sich mit C# entsprechende Archive automatisch erstellen lassen.

Das .NET-Framework liefert im Namensraum System.IO.Compression grundlegende Funktionalität zur Arbeit mit entsprechenden Archiven, auf die wir in diesem Beitrag setzen werden. Darüber hinaus gibt es jedoch eine Vielzahl weiterer Implementierungen (z. B. DotNetZip oder SharpZipLib), welche beispielsweise die Erstellung von passwortgeschützten Archiven ermöglichen und weitere Konfigurationsmöglichkeiten bieten.

Zuerst möchte ich ein paar Möglichkeiten aufzeigen, um ZIP-Archive zu erstellen:
Archiv aus bestehendem Verzeichnis erstellen
01
ZipFile.CreateFromDirectory("data", "data.zip");
Archiv aus bestehenden Dateien erstellen
010203040506
using(FileStream fileStream = File.OpenWrite("data.zip")) {    using(ZipArchive zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Create)) {        zipArchive.CreateEntryFromFile("data/a.txt", "a.txt");        zipArchive.CreateEntryFromFile("data/b.txt", "b.txt");    }}
Archiv manuell zusammenstellen
010203040506070809
using(FileStream fileStream = File.OpenWrite("data.zip")) {    using(ZipArchive zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Create)) {        ZipArchiveEntry zipArchiveEntry = zipArchive.CreateEntry("README");
using(StreamWriter streamWriter = new StreamWriter(zipArchiveEntry.Open())) { streamWriter.Write("Hallo Welt!"); } }}
Abschließend möchten wir auf bestehende Archive zugreifen:
Archiv vollständig entpacken
01
ZipFile.ExtractToDirectory("data.zip", "data");
Archiv einlesen und verarbeiten
01020304050607080910111213141516
using(FileStream fileStream = File.OpenRead("data.zip")) {    using(ZipArchive zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read)) {        foreach(ZipArchiveEntry zipArchiveEntry in zipArchive.Entries) {              // "README" separat berücksichtigen            if(zipArchiveEntry.Name == "README") {                using(StreamReader streamReader = new StreamReader(zipArchiveEntry.Open())) {                      // Inhalt einlesen und auf Konsole ausgeben                    Console.WriteLine(streamReader.ReadToEnd());                }            } else {                  // Eintrag als Datei speichern                zipArchiveEntry.ExtractToFile(zipArchiveEntry.Name);            }        }    }}
Sehr viel mehr Möglichkeiten stehen leider tatsächlich nicht zur Verfügung; für weitergehende Einstellungen gibt es jedoch beispielsweise die bereits erwähnten externen Bibliotheken. Durch die Verwendung von Datenströmen besteht aber grundsätzlich die Möglichkeit, nahezu beliebige Quellen (und Ziele) für Archiv-Einträge heranzuziehen.

Projektverweise

Kategorien / Archiv  |  Übersicht RSS-Feed

Schlagworte

Suche