Schlagwort: .NET

HttpHandler in ASP.NET MVC 👍 👎

Manchmal kann es sinnvoll sein, bestimmte Aufrufe einer Webanwendung abseits der "normalen" Vorgehensweise zu behandeln. Konkret soll es darum gehen, Aufrufe mit der Dateiendung ".css" abzufangen, um in den statischen Dateien Platzhalter dynamisch zu ersetzen, was mit CSS selbst nicht möglich wäre. Unser Stylesheet:
Site.css
01020304
body {    background-color: #{backgroundColor};    color: #{color};}
Die Umsetzung ist sehr einfach, wir müssen dazu lediglich eine Klasse erstellen, welche die Schnittstelle IHttpHandler und natürlich auch das gewünschte Verhalten implementiert – der Fantasie sind hier kaum Grenzen gesetzt. Wir belassen es der Einfachheit wegen bei einem einfachen (und nicht sehr effizienten) Beispiel:
HttpHandler implementieren
010203040506070809101112131415161718192021222324
public class HttpHandler : IHttpHandler {    public bool IsReusable {        get {            return true;        }    }
public void ProcessRequest(HttpContext context) { // Ersetzungsdaten (in der Praxis evtl. aus Datenbank) Dictionary<string, string> replacementData = new Dictionary<string, string>() { {"backgroundColor", "000"}, {"color", "fff"} };
// Platzhalter im Stylesheet mit Ersetzungsdaten austauschen StringBuilder css = new StringBuilder(File.ReadAllText("Site.css"));
foreach(KeyValuePair<string, string> replacement in replacementData) { css.Replace(String.Format("{{0}}", replacement.Key), replacement.Value); }
context.Response.Write(css.ToString()); }}
Abschließend passen wir die Konfiguration (→ Web.config) an, um unsere eigene Behandlung zu registrieren:
Konfiguration erweitern
01020304050607
<configuration>  <system.webServer>    <handlers>      <add name="DynamicStylesheet" path="*.css" type="HttpHandler" verb="GET" />    </handlers>  </system.webServer></configuration>
Weiterführende Informationen zum Thema finden sich im MSDN.

Ein bekanntes – und weitaus mächtigeres – Projekt, welches von dieser Möglichkeit Gebrauch macht, ist dotless, eine Implementierung der Stylesheet-Skriptsprache LESS für .NET. Diese ermöglicht u. a. eine übersichtlichere Verschachtelung, Variablen und Funktionen in Stylesheets, wobei der HttpHandler dafür sorgt, dass die vom Browser angeforderten .less-Dateien serverseitig in "reines" CSS umgewandelt und ausgeliefert werden.

Die Verwendung der MVC-Erweiterung für ASP.NET ist für dieses Vorgehen übrigens nicht unbedingt erforderlich, ich arbeite jedoch nahezu ausschließlich mit dieser.

Hashing in C# und PHP 👍 👎

Den meisten PHP-Entwicklern sind die beiden Funktionen md5(…) und sha1(…) geläufig. Diese liefern zu einer übergebenen Zeichenkette einen Streuwert ("Hash") in hexadezimaler Darstellung. Zu diesem Zweck gibt es in C# die beiden Klassen MD5CryptoServiceProvider und SHA1CryptoServiceProvider.

Diesen Klassen kann man über die ComputeHash-Methode unter anderem ein byte-Array übergeben und bekommt daraufhin ein solches zurück, welches den Hash darstellt. Da wir es in der Praxis aber doch meist einfach nur mit Zeichenketten und u. U. auch mit verschiedenen Hash-Algorithmen (z. B. MD5, SHA1) zu tun haben, möchten wir das Ganze in eine komfortable generische Erweiterungsmethode für Zeichenketten verpacken:
Methode implementieren
0102030405060708
public static string GetHash<T>(this string str) where T : HashAlgorithm, new() {    using(T hashProvider = new T()) {          // Streuwert berechnen        byte[] hash = hashProvider.ComputeHash(Encoding.UTF8.GetBytes(str));
return Encoding.UTF8.GetString(hash); }}
Für diejenigen, denen die Arbeit mit generischen Typen (noch) nicht geläufig ist, werde ich in Kürze auch noch einen etwas ausführlicheren Beitrag zu diesem Thema verfassen.

Die Rückgabe dieser Methode dürfte nun jedoch leider noch gar nicht dem entsprechen, was viele erwarten – die hexadezimale Schreibweise wie in PHP, so dass diese Ausgaben insbesondere nicht kompatibel zueinander für Vergleiche sind, was die Interoperabilität natürlich massiv beeinträchtigt. C# liefert standardmäßig nämlich das, was bei den entsprechenden PHP-Funktionen mit dem Parameter $raw_output erhältlich ist.

Da die hexadezimale Darstellung jedoch tatsächlich häufig praktikabler ist, stützen wir uns ausnahmsweise ( Smiley: winking) auf diese Vorgehensweise und bringen C# zu diesem – unter anderem von PHP gewohnten – Verhalten:
Methode implementieren (hexadezimale Rückgabe)
0102030405060708
public static string GetHash<T>(this string str) where T : HashAlgorithm, new() {    using(T hashProvider = new T()) {          // Streuwert berechnen        byte[] hash = hashProvider.ComputeHash(Encoding.UTF8.GetBytes(str));
return BitConverter.ToString(hash).Replace("-", String.Empty).ToLower(); }}
Jetzt liefert unsere Erweiterungsmethode für C# exakt das gleiche Ergebnis wie PHP das standardmäßig macht und kann darüber hinaus besonders einfach und flexibel auf jeder Zeichenkette verwendet werden:
Methode verwenden
01
string hashTest = "test".GetHash<SHA1CryptoServiceProvider>();
Durch Übergabe der gewünschten Implementierung als Typparameter erhalten wir nun direkt das Ergebnis.

eMail mit C# versenden 👍 👎

Weil mich diese Frage recht häufig erreicht, möchte ich hier einmal festhalten, wie man eine einfache eMail mit C# versenden kann. PHP-Entwickler verweisen dabei gerne auf die kompakte mail(…)-Funktion.

Da das auch in C# sehr einfach ist, präsentiere ich direkt den Quelltext und setze verstärkt auf Auflistungsinitialisierer, womit sich die relevanten Stellen quasi von selbst kommentieren:
eMail mit C# versenden
0102030405060708091011121314151617181920
  // SMTP-Client zum MailserverSmtpClient client = new SmtpClient("mail.domain.tld") {      // Authentifizierungsdaten setzen    Credentials = new NetworkCredential() {        UserName = "Benutzername",        Password = "Passwort"    }};
// Nachricht erstellenMailMessage message = new MailMessage() { From = new MailAddress("absender@domain.tld", "Absender"), Subject = "Test", Body = "Text"};
message.To.Add(new MailAddress("empfänger@domain.tld", "Empfänger"));
// Nachricht versendenclient.Send(message);
Wer keine weiteren Ansprüche wie HTML-Inhalt, Datei-Anhänge etc. hat, kann das eigentliche Senden durchaus auch mit einem Einzeiler – ähnlich wie in PHP – ohne das Erzeugen einer MailMessage bewerkstelligen:
eMail mit C# versenden (ohne MailMessage)
0102
  // Nachricht versendenclient.Send("absender@domain.tld", "empfänger@domain.tld", "Test", "Text");
Für weitere Informationen zum Thema sollte man sich hauptsächlich den Namensraum System.Net.Mail im MSDN näher ansehen. An dieser Stelle auch noch einmal der Hinweis darauf, Ressourcen wieder freizugeben, worauf ich bei meinen Beispielen für gewöhnlich verzichte, um den Fokus auf das konkrete Beispiel zu legen.

"??"-Operator in C# 👍 👎

In meinem Beitrag zu NULL für Werttypen in C# hatte ich bereits beschrieben, wie man Werttypen in C# (z. B. bool, int) indirekt dazu bewegen kann, auch null zu akzeptieren, was ansonsten ja nicht möglich ist.

Nun kann es hin und wieder (z. B. zur Arbeit mit externen Bibliotheken) jedoch notwendig sein, diesen Wert einer Variable grundsätzlich gleichen Typs zuzuweisen, die jedoch kein null akzeptiert. Behelfen kann man sich in derartigen Fällen selbstverständlich mit Konstrukten wie diesem:
Zuweisung ohne ??-Operator
010203040506
bool? isValid = null;
bool isRealValid = false;if(isValid.HasValue) { isRealValid = isValid.Value;} // "isRealValid" enthält "false", wenn "isValid" (ebenfalls) "false" oder "null" ist
Etwas kompakter geht es jedoch mit dem ??-Operator (nicht zu verwechseln mit dem ternären ?:-Operator):
Zuweisung mit ??-Operator
01020304
bool? isValid = null;
bool isRealValid = isValid ?? false;// "isRealValid" enthält "false", wenn "isValid" (ebenfalls) "false" oder "null" ist
Der Wert hinter dem Operator dient also als Ersatzwert für null. In beiden Fällen gilt jedoch zu beachten, dass die ursprüngliche Semantik nicht erhalten bleibt. Einem reinen Werttyp kann nun einmal kein null zugewiesen werden, d. h. man muss sich für diesen Fall einen angemessenen Ersatz (z. B. -1 für int) suchen.

Im Übrigen funktioniert das mit beliebigen Referenztypen (deren Wert schließlich immer null sein darf), womit sich beispielsweise bequem Standardobjekte zuweisen lassen:
Standardobjekt per ??-Operator zuweisen
01020304050607080910
/** * "dbUser" soll z. B. aus einer Datenbank * kommen, wurde dort jedoch nicht gefunden.**/User dbUser = null;
User user = dbUser ?? new User() { Nickname = "Gast", IsGuest = true}; // "user" ist ein Gast, wenn "dbUser" auf "null" steht

Mehrdimensionale und verzweigte Felder in C# 👍 👎

Eindimensionale Felder in C# sind schnell eingeführt und verwendet, dazu hatte ich auch schon einmal etwas im Zusammenhang mit PHP geschrieben. Bei den weiteren Varianten des Arrays in C# kann man grundsätzlich zwischen zwei Möglichkeiten unterscheiden: Mehrdimensionale und Verzweigte ("Array von Arrays"). Wir möchten uns daher beide einmal näher ansehen und beginnen zuerst mit dem mehrdimensionalen Feld:
Mehrdimensionales Feld
0102030405
int[,] matrix = new int[,] {    {11,12,13,14,15},    {21,22,23,24,25},    {31,32,33,34,35}};
Während es sich bei eindimensionalen Feldern mathematisch betrachtet um Vektoren handelt, handelt es sich hierbei um eine m*n-Matrix (mit 3 Zeilen und 5 Spalten); analog dazu wären auch dreidimensionale Gebilde etc. möglich. Wichtig zu erkennen ist an dieser Stelle, dass es sich tatsächlich um eine rechteckige Anordnung (nicht jedoch zwangsläufig um eine quadratische) handelt, d. h. jede Zeile besitzt gleich viele Spalten.

Wir können anschließend wie folgt damit arbeiten:
Elemente durchlaufen
0102030405060708091011121314151617181920212223242526272829
  // Verschachtelte Schleifenfor(int m = 0; m < 3; m++) {      // Zeilen    for(int n = 0; n < 5; n++) {  // Spalten        /**         * matrix[m, n] enthält das         * entsprechende Element.        **/    }}
// Einfache Schleifefor(int i = 0; i < matrix.Length; i++) { // matrix.Length = (3 * 5) /** * matrix[i / 5, i % 5] enthält * das entsprechende Element. * * C++-Entwickler mögen an dieser Stelle * an *(*matrix + i) denken, was man bei * C# jedoch nur "unsafe" bekommt. **/}
// FOREACH-Schleifeforeach(int x in matrix) { /** * "x" enthält nun das * entsprechende Element. **/}
Eine weitere Möglichkeit sind nun die sog. verzweigten Felder:
Verzweigtes Feld
0102030405
int[][] data = new int[][] {    new int[] {11,12,13},    new int[] {21,22,23,24},    new int[] {31,32,33,34,35}};
Bereits die Initialisierung verdeutlicht sehr gut, dass es sich wie bereits erwähnt um ein Array von Arrays handelt, wobei jeder Eintrag nun ein Feld "beliebiger" Länge sein kann. Beim Durchlaufen – diesmal im Allgemeinen natürlich nur noch mit verschachtelten Schleifen möglich – wird dies noch einmal dadurch betont, dass wir die entsprechende Length-Eigenschaft (auch) für die innere Schleife nutzen können (und werden):
Elemente durchlaufen
01020304050607080910111213141516171819
  // FOR-Schleifenfor(int i = 0; i < data.Length; i++) {    for(int j = 0; j < data[i].Length; j++) {        /**         * data[i][j] enthält das         * entsprechende Element.        **/    }}
// FOREACH-Schleifenforeach(int[] i in data) { foreach(int j in i) { /** * "j" enthält nun das * entsprechende Element. **/ }}
Derartige Felder werden übrigens oft auch "jagged array" genannt. Zuletzt sei noch erwähnt, dass sich beide Formen durchaus auch kombinieren lassen. Weitere Informationen und Beispiele gibt es wie üblich im MSDN.

Projektverweise

Kategorien / Archiv  |  Übersicht RSS-Feed

Schlagworte

Suche