Kategorie: Softwareentwicklung

Quelltext einer Webseite mit C# einlesen 👍 👎

Manchmal kann es sinnvoll sein, den Quelltext einer Webseite automatisiert abzurufen, beispielsweise um Tests durchzuführen. Dies lässt sich in C# sehr einfach über die HttpWebRequest-Klasse lösen:
Quelltext per HttpWebRequest einlesen
01020304050607
HttpWebRequest request = HttpWebRequest.CreateHttp("http://domain.tld/");
using(WebResponse response = request.GetResponse()) { using(StreamReader streamReader = new StreamReader(response.GetResponseStream())) { string content = streamReader.ReadToEnd(); }}
Noch kompakter lässt sich das Ganze mit Hilfe der Klassen WebClient oder HttpClient lösen:
Quelltext per WebClient oder HttpClient einlesen
010203040506070809101112131415161718
  // WebClientusing(WebClient webClient = new WebClient()) {      // blockierend    string content = webClient.DownloadString("http://domain.tld/");
// nicht blockierend webClient.DownloadStringCompleted += (sender, e) => { string content = e.Result; };
webClient.DownloadStringAsync(new Uri("http://domain.tld/"));}

// HttpClientusing(HttpClient httpClient = new HttpClient()) { string content = await httpClient.GetStringAsync("http://domain.tld/");}
Abschließend sei bemerkt, dass diese Möglichkeit nicht für fragliche Aktionen genutzt werden sollte – dazu gehört im Übrigen auch schlicht unnötiger Traffic. Smiley: winking

(Pseudo-)Zufallszahlen in C# 👍 👎

Sehr häufig benötigt man in div. Anwendungen zufällige Zahlen (oder zumindest solche, die sich hinreichend ähnlich verhalten). Hierfür steht uns in C# die grundlegende Klasse Random zur Verfügung:
Random-Klasse verwenden
0102030405060708091011121314
Random random = new Random();
int randomInt = random.Next(); // Intervall: [0,Int32.MaxValue)int randomIntMax = random.Next(8); // Intervall: [0,8) bzw. [0,7]int randomIntMinMax = random.Next(5, 19); // Intervall: [5,19) bzw. [5,18]
/** * Befüllt "randomData" mit * zufälligen Byte-Werten.**/
byte[] randomData = new byte[3];random.NextBytes(randomData);
double randomDouble = random.NextDouble(); // Intervall: [0,1)
Manche Entwickler sind ggf. erst einmal etwas auf Grund der oberen Grenze verwirrt, welche bei Verwendung der entsprechenden Methoden exklusiv ist. Das bedeutet, dass ihr das eigentlich gewünschte Maximum inkrementiert angeben müsst, sofern dieses ebenfalls enthalten sein soll.

Die Verwendung gestaltet sich dennoch offensichtlich sehr einfach. Zu berücksichtigen gilt jedoch, dass als Seed standardmäßig ein zeitabhängiger Wert verwendet wird – um dieses Verhalten selbst zu steuern, existiert eine weitere Variante des Konstruktors. Gleiche Startwerte ergeben wie üblich gleiche Sequenzen an Zufallszahlen.

Für sensiblere Anwendungen, beispielsweise zur Schlüsselgenerierung, steht der kryptografische Zufallszahlengenerator RNGCryptoServiceProvider als konkrete Implementierung der abstrakten Basisklasse RandomNumberGenerator zur Verfügung. Die Verwendung gestaltet sich ähnlich einfach:
RNGCryptoServiceProvider-Klasse verwenden
01020304050607080910111213
using(RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) {      // 3 Zufallszahlen erzeugen    byte[] randomData = new byte[3];    rng.GetBytes(randomData);
// Zufalls-Bytes durchlaufen foreach(byte randomNumber in randomData) { /** * "randomNumber" enthält nun jeweils * eine der erzeugten Zufallszahlen. **/ }}
Weitere sinnvolle Hinweise finden sich in den jeweiligen Klassenbeschreibungen des MSDN.

Benutzerdefinierte Validierung unter ASP.NET MVC 👍 👎

Sehr praktisch unter ASP.NET MVC sind Attribute zur Validierung in Models. Standardmäßig bietet das .NET-Framework im Namensraum System.ComponentModel.DataAnnotations beispielsweise die Attribute Range, Required und StringLength, deren Verwendung wohl selbsterklärend sein dürfte.

Manchmal benötigt man jedoch etwas speziellere Validierungen und möchte naheliegenderweise dennoch auf eine einheitliche Vorgehensweise setzen. Hierfür steht das (abstrakte) Attribut Validation zur Verfügung, von welchem wir eine konkrete Implementierung für unser Vorhaben ableiten können.

Für unser Beispiel möchten wir ein Attribut zur Validierung implementieren, welches angibt, dass ein Feld (üblicherweise indirekt aus einem Formular vom Benutzer befüllt) mindestens eine Ziffer, zwei Großbuchstaben und drei Kleinbuchstaben enthalten muss. Wir halten es bewusst einfach, um uns auf den Kontext zu konzentrieren:
Benutzerdefiniertes Attribut zur Validierung implementieren
010203040506070809101112131415161718
[AttributeUsage(AttributeTargets.Property)]public class PasswordAttribute : ValidationAttribute {    public override bool IsValid(object value) {        string val = value as string;
if(!String.IsNullOrWhiteSpace(val)) { return ( val.Count(c => Char.IsDigit(c)) >= 1 && val.Count(c => Char.IsUpper(c)) >= 2 && val.Count(c => Char.IsLower(c)) >= 3 ); } else { return false; } }}
Dies ist eine sehr grundlegende Implementierung, die sich durchaus noch erweitern (und optimieren) lässt. Grundsätzlich genügt dieses Vorgehen jedoch bereits, um Verwendung zu finden. Das Attribut wird dazu wie üblich über der entsprechenden Eigenschaft der Model-Klasse deklariert:
Benutzerdefiniertes Attribut zur Validierung verwenden
01020304050607
public class User {    [Password]    public string Password {        get;        set;    }}
Eine allgemeine Einführung zum MVC-Framework möchte ich gerne in einem späteren Beitrag liefern.

Datei per ASP.NET MVC ausliefern 👍 👎

Häufig möchte man auf seiner Webpräsenz nicht nur mit HTML-Ansichten arbeiten, sondern beispielsweise auch Dateien zum Herunterladen anbieten. Das ist selbstverständlich auch unter ASP.NET MVC kein Problem, sondern erfordert lediglich eine Aktion mit dem Rückgabetyp FileResult.

Hierbei handelt es sich jedoch um eine abstrakte (Basis-)Klasse, konkrete Implementierungen stehen mit FileContentResult, FilePathResult und FileStreamResult zur Verfügung. Wir begnügen uns mit einem minimalistischen Beispiel und verwenden FilePathResult – was soweit selbsterklärend sein dürfte:
Download-Aktion im Controller "Gallery"
01020304050607
public class GalleryController : Controller {    public FileResult Download() {        return new FilePathResult(@"X:\Pfad\zur\Datei\MeinBild.png", "image/png") {            FileDownloadName = "Bild.png"  // Dateiname für Benutzer festlegen        };    }}
Sofern FileDownloadName gesetzt wird, sollte der Browser die Datei automatisch zum Speichern anbieten, ansonsten greift das jeweilige Standardverhalten. Weitere Möglichkeiten bieten euch die bereits erwähnten anderen Implementierungen, natürlich könnt ihr auch jederzeit selbst welche für eure eigenen Bedürfnisse ableiten.

Rundung in C# (und PHP) 👍 👎

Rundung erscheint auf den ersten Blick so selbstverständlich, dass so mancher geneigt scheint, sich darüber gar keine großen Gedanken zu machen. Beim Ab- und Aufrunden mit Methoden wie Math.Floor und Math.Ceiling gibt es auch tatsächlich keine großen Überraschungen bei den meisten Programmiersprachen:
Auf- und Abrunden
010203040506070809
  // Abrundungdouble floor1 = Math.Floor(1.3);  // 1double floor2 = Math.Floor(1.5);  // 1double floor3 = Math.Floor(1.7);  // 1  // Aufrundungdouble ceiling1 = Math.Ceiling(1.3);  // 2double ceiling2 = Math.Ceiling(1.5);  // 2double ceiling3 = Math.Ceiling(1.7);  // 2
Spannend wird es jedoch beim allgemeineren Rundungsverfahren mit Math.Round, bei welchem sich das Verhalten standardmäßig zu dem unterscheiden kann, was man beispielsweise aus der Schule als kaufmännisches Runden oder vom Standardverhalten von round aus PHP kennt. Der Unterschied liegt konkret beim Rundungsverhalten an der Ziffer 5:
Rundungsverhalten an der Ziffer "5"
01020304050607
double rounded11 = Math.Round(2.3);  // 2double rounded12 = Math.Round(2.5);  // 2 (!)double rounded13 = Math.Round(2.7);  // 3
double rounded21 = Math.Round(7.3); // 7double rounded22 = Math.Round(7.5); // 8double rounded23 = Math.Round(7.7); // 8
Die Ursache für dieses für manche möglicherweise überraschende Verhalten liegt darin begründet, dass bei C# das mathematische Rundungsverfahren zur Anwendung kommt, welches in so einem Fall standardmäßig die Rundung zur nächsten geraden Ziffer vorschreibt, anstatt pauschal aufzurunden. Das Anliegen dabei ist es, statistische Verzerrungen durch ausschließliches Aufrunden an dieser Stelle zu vermeiden. Dies ist in jedem Fall bei der Interoperabilität mit anderen Systemen, die auf eine gleiche Datenbasis zugreifen, zu berücksichtigen.

Sowohl bei C# als auch bei PHP lässt sich dieses Verhalten jedoch manuell anpassen (und dadurch nötigenfalls angleichen), indem man unter C# einen Wert der Enumeration MidpointRounding oder unter PHP eine der Konstanten PHP_ROUND_HALF_* an die entsprechende Methode/Funktion zur Rundung übergibt.

Projektverweise

Kategorien / Archiv  |  Übersicht RSS-Feed

Schlagworte

Suche