BigBasti's Blog About Me & my Digital Lifestyle

17Sep/110

Nice2Know: Attribut-basierende Routen in ASP.NET MVC

Für Routen ist in ASP.NET MVC für gewöhnlich die Global.asax zuständig, so werden hier alle Routen definiert und gemappt. Doch wenn man viele verschiedene Routen nutzen will wird es schnell voll in der eigentlich sehr übersichtlichen Klasse.

Da wäre es doch eigentlich cool wenn wir die Routen direct in unseren Controllern definieren könnten. Genau das können wir mit der Erweiterung AttributeRouting machen.

Installation

Installation über NuGet

Dank NuGet ist die Installation in wenigen Sekunden abgeschlossen und wir können unsere Actions mit Routing-Attributen dekorieren.

Die Attribute sind hierbei sehr einfach gestaltet und bieten uns alles was wir benötigen.


    public class DemoController : Controller
    {
        [GET("Ist/Das/Cool/Oder/Was")]
        public ActionResult Start()
        {
            return View();
        }
    }

Nun muss man nur noch die Attribut-basierten Routen registrieren:


    public static void RegisterRoutes(RouteCollection routes) {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapAttributeRoutes(); //--- das wars!

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Start",
                id = UrlParameter.Optional } // Parameter defaults
        );
    }

Und fertig! Nun können wir die Seite starten und unsere Route testen:

Das Ergebnis

Das Ergebnis

Die Routen die wir definieren können, beschränken sich nicht darauf, so können diese auch problemlos parametrisiert werden, inklusive Defaultparameter:


    public class DemoController : Controller
    {
        [GET("Artikel/{artikelid}/{version?}")]
        [RouteDefault("artikelid", "120")]
        public ActionResult Start(int artikelid, string version)
        {
            ViewBag.ArtikelId = artikelid;
            ViewBag.Version = version;

            return View();
        }
    }

Hier wird der Parameter artikelid mit einem Defaultwert ausgestattet und der zweite optional gemacht. Das Ergebnis kann sich sehen lasen:

Läuft!

Läuft!

Hier hört das Framework nicht auf, so könnt ihr auch Regular Expressions in die Routen integrieren und auch mehrere Routen an eine Action heften. Die Möglichkeiten sind grenzenlos ;)

Für weitere Infos schaut einfach auf der Projekthomepage vorbei, es lohnt sich!

11Sep/114

Lokale Wetterdaten anzeigen mit der HTML5 Geolocation API und ASP.NET MVC

Wenn man heutzutage hipp sein will mit seiner Webseite sollte man irgendwelche coolen Features von HTML5 nutzen. Deswegen möchte ich euch in diesem kleinem Tutorial zeigen, wie ihr auf eurer Seite dem aktuellen Besucher sein lokales Wetter anzeigen könnt.

Um dieses Ziel zu verwirklichen benötigen wir folgende Daten bzw. Dienste:

  1. Die physische Position des Besuchers
  2. Einen Dienst der uns zu der Position des Besuchers die Wetterdaten liefert

Der erste Punkt ist schnell abgehackt, denn hier werden wir eins der tollen neuen HTML5 Features namens Geolocation API benutzen. Diese API liefert uns, vorausgesetzt der Browser unterstützt es, Koordinaten des aktuellen Besuchers der Webseite. Alle aktuellen Browser, auch der IE ab Version 9 unterstützt diese API.

Das Ganze läuft so ab, dass wir als Webseite den Browser nach den Koordinaten fragen, aber dieser uns diese nicht sofort herausrückt, sondern erst den Benutzer fragt ob er einverstanden ist, das sieht je nach Browser unterschiedlich aus, hier ein Beispiel aus dem FireFox 6:

Wenn der Benutzer hier auf die “Zugriff erlauben” Schaltfläche klickt bekommen wir ein Objekt mit einem Haufen an Informationen rund um die Position des Benutzers. Für uns ist an dieser Stelle aber nur die Adresse des Nutzers von Bedeutung.

Moment mal, woher weiß der Browser so ich bin?

Tja, das ist eine gute Frage, auf magische Weise weiß der Browser wo wir uns aufhalten, auch wenn wir grad mit einem Desktopcomputer auf der Seite sind, der kein GPS Chip verbaut hat (im Vergleich zum Handy – wo das ja klar sein sollte) und das auch noch _ziemlich_ genau!

Im ersten Augenblick könnte man denken der Browser macht es über die IP Adresse, aber nein die IP ist _Viel_ zu ungenau im Vergleich mit den echten Koordinaten.

So sendet der Browser (Firefox) nach eurer Erlaubnis folgende Daten an Google unter dieser Adresse: https://www.google.com/loc/json


"mac_address": "01-23-45-67-89-ab",
"signal_strength": 8,
"age": 0,
"SSID": "MyAccessPoint"

Weitere Informationen

Als Google mit ihren StreetView Autos durch die Gegend gefahren ist haben die nämlich auch die Namen und die genauen Positionen von den WLAN Netzwerken gespeichert, an denen sie vorbeigefahren sind. An Hand dieser Informationen versucht Google euch nun zu orten.

Wie komme ich nun an diese Informationen?

Glücklicherweise gestaltet sich dies für uns sehr einfach:


if (navigator.geolocation) {
  navigator.geolocation.getCurrentPosition(success, error);
} else {
  alert("Not Supported!");
}

Wenn der Browser diese API kennt werden die statischen Klassen Navigator und geolocation aufgerufen und hier die Methode getCurrentPosition aufgerufen, diese bekommt als Parameter einen Verweis auf die Methode die ausgeführt werden soll. Wenn das Ganze fehlschlägt (Kein Browsersupport) soll die display_error-Methode aufgerufen werden.

Die Funktion success bekommt einen Parameter mit, der alle relevanten Informationen enthält:
<pre>


function success(position) {
alert(position.coords.latitude);
alert(position.coords.longitude);
alert(position.address.city);
}

Für uns ist für das weitere Vorgehen aber nur der Name der Stadt wichtig.

Auslesen der Wetterinformationen

Es gibt diverse offene APIs die uns die Wetterdaten zu einer angegebenen Stadt liefern können, ich habe mich an dieser Stelle für die von Google entschieden, da diese offen ist und keine Registrierung voraussetzt.

Die API ist unter folgender URL zu erreichen:

http://www.google.com/ig/api?weather=[LOCATION]&hl=[LANGUAGE]

Hier müsst ihr lediglich die gewünschte Stadt und die gewünschte Sprache einsetzen. Als Antwort bekommt ihr eine XML, die die Wetterdaten enthält, und das nicht nur für jetzt, sondern für die gesamte nächste Woche, inklusive ausgeschriebener Formulierungen wie “Teils sonnig” oder “Meistens bewölkt”.

Und wenn euch das noch nicht genug ist, bietet Google auch gleich das passende Icon zu dem Wetter, dass ebenfalls aus dem XML.Status ausgelesen werden kann. Insgesamt gibt es 22 verschiedene Wetterzustände zu denen es jeweils auch ein passendes Icon gibt.

Moment, wie komme ich nun an diese Daten?

Es besteht nun nur noch ein kleines Problem. Die ganze Abfrage erfolgt beim Client, deswegen kennt nur der Client die Position des Benutzers. Wir müssen nun aber (im Hintergrund => Ajax) einen Request an den Google Dienst absenden um an die Wetterdaten zu kommen.

Leider können wir das nicht direkt aus dem Client machen, da die Browser es verbieten, Requests an andere Domains abzusenden als an die von der das Script geladen wurde. Das ganze schimpft sich “Same Origin Policy” und soll den Benutzer unter Anderem vor Cross-Site-Scripting-Attaken schützen.

Das bedeutet, dass wir den Umweg über den Server gehen müssen und uns auf dem Server eine kleine API anlegen müssen die unserem Script auf Anfrage die passenden Daten liefert.

Dies kann man z.B so implementieren:


private const string GOOGLE_WEATHER_API_URL =
	"http://www.google.com/ig/api?weather={0}&amp;amp;amp;amp;amp;amp;amp;hl=de";
public WeatherResult GetWeahterData(string city) {

    string api_url = string.Format(GOOGLE_WEATHER_API_URL, city);

    try {
        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(api_url);
        HttpWebResponse res = (HttpWebResponse)req.GetResponse();
        StreamReader reader = new StreamReader(res.GetResponseStream());

        string response = reader.ReadToEnd();

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(response);

        string temp = xmlDoc.SelectSingleNode("xml_api_reply/weather/current_conditions/temp_c").Attributes["data"].Value;
        string icon = xmlDoc.SelectSingleNode("xml_api_reply/weather/current_conditions/icon").Attributes["data"].Value;

        WeatherResult wRes = new WeatherResult(temp, city);
        wRes.Icon = icon;

        return wRes;
    } catch (Exception ex) {
        return null;
    }
}

Für den Response habe ich mir eine kleine Klasse gebastelt, die ich zu Json serialisiere und als Antwort zurückgebe:


    public class WeatherResult {
        public string Temperature { get; set; }
        public string City { get; set; }
        public string Icon { get; set; }

        public WeatherResult(string temp, string city) {
            Temperature = temp;
            City = city;
        }
    }

Das Ganze wird von dem ApiController aufgerufen:


    public class ApiController : Controller
    {
        //
        // GET: /Api/GetWeather

        public JsonResult GetWeather(string id)
        {

            WeatherResult res = new Tools.Weather.WeatherHelper().GetWeahterData(id);

            return Json(res, JsonRequestBehavior.AllowGet);
        }

    }

Was wir nun noch machen müssen ist unsere neu geschaffene API über einen Ajax Request aufzurufen. Hier habe ich jQuery benutzt um das Ganze zu vereinfachen:


function get_address(position) {
    var full_url = "/Api/GetWeather/" + position.address.city;

    $.ajax({
        url: full_url,
        success: get_weather,
        error: display_error
    });
}

Die get_weather-Funktion auf die ich hier im Erfolgsfall verweise ist nun dafür verantwortlich die vom Server erhaltenen Daten anzuzeigen, und dank dem zu Json serialisiertem WeatherResult-Objekt kann dies auch bequem erfolgen. Hier habe ich ebenfalls jQuery genutzt um mir die benötigten Referenzen auf die DOM-Objekte zu besorgen. Ein mögliches Ergebnis des Ganzen könnte ihr hier rechts sehen.


function get_weather(address) {

    $(".weather_info").html(address.Temperature == "" ? "N/A" : address.Temperature + "°C");
    $(".location_info").html(address.City);

}

Sonst noch was?

Im Grunde wars das auch schon. Aber eine Kleinigkeit ist mir noch aufgefallen, und zwar kann es vorkommen, dass ihr keine Adressdaten von der Geolocation API bekommt, sondern nur Koordinaten. (Falls Google diese Daten nicht gelistet hat oder ähnliches).

In diesem Fall müsst ihr ein Reverselookup machen und die Koordinaten in eine Adresse umwandeln, da die Google Wetter API nur Ortsnamen, aber keine Koordinaten annimmt.

Glücklicherweise stellt und Google auch dafür eine API zur Verfügung, diese könnt ihr unter folgender URL erreichen:

http://maps.google.com/maps/api/geocode/json?latlng=[KOORDINATEN]sensor=true 

Hier könnt ihr sogar als Parameter angeben, ob ihr XML oder Json als Antwort haben wollt. Diese könnt ihr z.B. so nutzen:


private const string GOOGLE_MAPS_REVERSE_LOOKUP_URL =
	"http://maps.google.com/maps/api/geocode/json?latlng={0}&amp;amp;amp;amp;amp;amp;amp;sensor=true";
public static string GetCityFromCoords(string coords) {
    string api_url = String.Format(GOOGLE_MAPS_REVERSE_LOOKUP_URL, coords);

    try {
        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(api_url);
        HttpWebResponse res = (HttpWebResponse)req.GetResponse();
        StreamReader reader = new StreamReader(res.GetResponseStream());

        string response = reader.ReadToEnd();

        var serializer = new JavaScriptSerializer();
        serializer.RegisterConverters(new[] { new DynamicJsonConverter() });

        dynamic obj = serializer.Deserialize(response, typeof(object));

        string city = obj.results[0].address_components[3].long_name;

        return city;
    } catch (Exception ex) {
        return "";
    }
}

Hier habe ich mir ein dynamic-Object generieren lassen aus dem übergebenen Json. Dazu habe ich diese Klasse hier genutzt.

Falls dieser Fall eintreffen sollte, braucht ihr übrigens nicht mit genauen Koordinaten bzw. Adressdaten zu rechnen, aber für unseren Zweck reicht es allemal.

kick it on dotnet-kicks.de

8Aug/110

Anonyme Threaduebergreifende Eventhandler

Jeder von uns uns hatte schon mit Events und den dazugehörigen Handlern zu tun. Jeder Button auf einem Formular hat z.B. einen eigenen Eventhandler, der irgendwo in der Form.Designer.cs definiert und registriert wird. Dieser sieht dann meist ca so aus:


//Registrierung
this.button1.Click += new System.EventHandler(this.button1_Click);
//Verweis / Nutzung
private void button1_Click(object sender, EventArgs e) { }

So wird jedes Mal wenn des Click-Event der Button-Instanz ausgelöst wird die registrierte Methode button1_Click Ausgeführt. Eigentlich ein schönes und einfaches System, aber wenn man eigene Klassen hat und teilweise viele Instanzen davon bildet ist es unschön, da dabei sehr viele Methoden in der Klasse entstehen und somit  die Übersicht mit der Zeit verloren geht.

Deswegen gibt es für uns die Möglichkeit so genannte anonyme Methoden als EventHandler zu verwenden. Diese benötigen keine Deklaration und haben keine Referenz, somit gehen diese auch verloren, sobald diese zu Ende gelaufen sind. Benutzen kann man diese so:


this.button1.Click += delegate(object sender, EventArgs e) {
    //hier steht mein Code
};

Wie man sieht ist der Code um einiges übersichtlicher geworden und kürzer geworden. Wir übergeben nun eine anonyme Methode als Handler.

Was das ganze noch etwas interessanter macht, ist dass es noch mehr Ersparnis und noch mehr Übersicht bei Threadübergreifenden EventHandlern gibt. Schauen wir uns mal an wie es normalerweise ausschaut:


//Registrierung des EventHandler zum anderen Thread
man.NewInformationUpdate += new NewInformationUpdateArrived(update_received);

//Handlermethode
public void update_received(object sender, TestInformationUpdateEventArgs ev) {
    //Aufruf zu dem eigenen Thread deligieren
    this.BeginInvoke(new delegateupdate(update), new object[] { ev });
}

//Definition der delegaten Methode
public delegate void delegateupdate(TestInformationUpdateEventArgs ev);

//Eigentliche Methode zum Verarbeiten des Events
private void update(TestInformationUpdateEventArgs msg) {
//...
}

Wir haben nun drei Methoden definiert, nur um ein Event zu behandeln, dies ist von Nöten, da wir hier Events verarbeiten, die aus einem anderen Thread kommen.

Hier können wir ebenfalls viel einsparen wenn wir mit delegates und anonymen Methoden arbeiten:


fd1.CompletionInformation += delegate(object se, CompletionInformationArgs ci) {
    this.BeginInvoke(new EventHandler(delegate(object obj, EventArgs ea) {
        CompletionInformationArgs cea = (CompletionInformationArgs)ea;

        //Unser verabeitungs Code hier

    }), new object[] { se, ci });
};

Hier haben wir wieder aus drei Methoden eine gemacht, naja eine richtige zumindest ;) und zwei anonyme. Ich finde diese Variante deutlich lesbarer und übersichtlicher, da alle wichtigen Information an einer Stelle sind.

Doch Vorsicht, diese Methode hat einen gravierenden Nachteil, da wir hier anonyme Methoden benutzen haben wir keine Referenz darauf und können somit das registrierte Event nie wieder un-registrieren. Mit anderen Worten, man muss abwegen wann man diese Abkürzung gehen kann und wann nicht.

Meiner Erfahrung nach wird der Fall überwiegen wo man diesen Weg leider nicht gehen kann, aber dann kann man versuchen ein Zwischenweg zu finden:


    var handler = new EventHandler(delegate(object o, EventArgs e)
    {
        //handler Logik
    };

    Subject.NewEvent += handler;

    //Diesen können wir später dann auch entfernen
    Subject.NewEvent -= handler;

Auf diese Weise haben wir immernoch eine Ersparnis und behalten die volle Kontrolle über unsere Handler.

Als kleine (unschöne) Alternative können wir auch anonyme Handler loswerden, indem wir alle Handler entfernen:


        public event EventHandler SomeEvent;

        public void ClearEventHandlers() {
            Delegate[] delegates = SomeEvent.GetInvocationList();
            foreach (Delegate delegate in delegates) {
                SomeEvent -= (EventHandler) delegate;
            }
        }

8Mai/114

Benutzerregistrierung mit ASP.NET MVC und jQuery Teil 1

Wer heute Webanwendungen erstellt kommt einfach nicht drumherum JavaScript zu verwenden um dem Benutzer zb. die Eingabe von Daten in ein Formular zu erleichtern und zB. Hinweise während der Eingabe anzuzeigen.

Leider ist JavaScript bei vielen nicht wirklich beliebt und die meisten versuchen wann immer es geht darauf zu verzichten, und das auch aus guten Gründen, denn ähnlich wie mit dem HTML Standard arbeiten die verschiedenen Browser in einigen Bereichen etwas eigenwillig, das kann einen schon mal zur Verzweifelung treiben.

Das haben sich auch viele andere gedacht und so gibt es inzwischen viele Frameworks die dem Entwickler viel Arbeit abnehmen und sich um diese fiesen Sachen wie die Kompabilität zu Browsern kümmern. In meinem Beispiel hier möchte ich euch das JavaScript Framework jQuery vorstellen.

Warum jQuery?

jQuery ist inzwischen in der Version 1.5.1 verfügbar und ist kompatibel zu allen Browsern, desweiteren ist die Community sehr groß und es existieren hunderte von Plugins die ich nutzen könnt. Aber die wirklich guten Gründe sind, dass es über eine sehr sehr gute Dokumentation verfügt, alle Browser inklusive des IE9 unterstützt und offiziell von Microsoft supportet wird. Wenn ihr also beispielsweise ein neues ASP.NET (MVC) Projekt erstellt werdet ihr feststellen, dass ihr im Scripts-Ordner bereits die jQuery Scripte hinterlegt habt.

Was macht dieses Framework eigentlich?

jQuery wie der Name es schon sagt zeigt seine ganze Stärke in der Auswahl bzw. der Selektion von Webseitenelementen im DOM, so kann man mit einfachen Einzeilern ganze Webseiten-Bereiche modifizieren. Außerdem bietet jQuery Funktionen die man häufig nutzt wie zB. Asynchrone Ajax aufrufe oder Animationen von Feldern. Aber gut kommen wir zu unserem Beispiel.

Unser Beispiel

Als Beispiel möchte ich hier ein einfaches Registrierungsformular erstellen, dass wir dann mit jQuery aufwerten wollen. Dabei möchte ich hier den manuellen Weg gehen und nicht die in ASP.NET MVC3 integrierten Methoden nutzen, eventuell können wir ja ein einem zweiten Teil dann den anderen Weg darstellen.

Beginnen wir erstmal mit dem Model. Da wir unsere Registrierung simpel halten wollen muss der Benutzer nur drei Angaben machen, nämlich seinen Namen, Email Adresse und ein Passwort. Normalerweise würden wir unser model hier ca so gestalten:


public class RegisterModel {

    [Required]
    [DisplayName("Benutzername")]
    [Remote("CheckUserName", "Validation")]
    public String UserName { get; set; }

    [Required]
    [DisplayName("E-Mail Adresse")]
    [DataType(DataType.EmailAddress)]
    [Remote("CheckUserEmail", "Validation")]
    public String UserMail { get; set; }

    [Required]
    [DisplayName("Passwort")]
    [Remote("CheckUserNPassword", "Validation")]
    public String UserPass { get; set; }

    [Required, Compare("UserPass")]
    [DisplayName("Passwort wiederholen")]
    public String UserPass2 { get; set; }
}

Da wir das aber selber machen wollen und teils clientseitig validieren wollen schwächen wir das mal etwas ab und nehmen alles raus bis auf das DisplayName Attribut:


public class RegisterModel {
    [DisplayName("Benutzername")]
    public String UserName { get; set; }

    [DisplayName("E-Mail Adresse")]
    public String UserMail { get; set; }

    [DisplayName("Passwort")]
    public String UserPass { get; set; }

    [DisplayName("Passwort wiederholen")]
    public String UserPass2 { get; set; }
}

So, nachdem wir das Model nun fertig haben, bauen wir das Projekt ein Mal und erstellen unsere View. Hier habe ich eine simple Tabelle angefertigt, die die nötigen Form-Elemente beinhaltet, die der Benutzer ausfüllen soll:


<div id="register_form">

<div id="headline">Registrierung</div>

�
<form id="registration_form" action="/Register" method="post">

<table border="1">
<tbody>
<tr>
<td>@Html.LabelFor(model => model.UserName):</td>
<td>@Html.TextBoxFor(model => model.UserName)</td>
<td><span id="UserName_error"> </span></td>
</tr>
<tr>
<td>@Html.LabelFor(model => model.UserMail):</td>
<td>@Html.TextBoxFor(model => model.UserMail)</td>
<td><span id="UserMail_error"> </span></td>
</tr>
<tr>
<td>@Html.LabelFor(model => model.UserPass):</td>
<td>@Html.TextBoxFor(model => model.UserPass)</td>
<td><span id="UserPass_error"> </span></td>
</tr>
<tr>
<td>@Html.LabelFor(model => model.UserPass2):</td>
<td>@Html.TextBoxFor(model => model.UserPass2)</td>
<td><span id="UserPass2_error"> </span></td>
</tr>
<tr>
<td></td>
<td><input id="submit_form_button" type="submit" value="Registrierung abschicken" /></td>
<td></td>
</tr>
</tbody>
</table>

�
</form>

�
</div>

Hier benutze ich die neue Razor Syntax von ASP.NET MVC3 falls ihr damit noch nicht vertraut seid könnt ihrhier mal gucken.

So sieht das Beispielformular aus

Die erste Spalte enthält hier jeweils die Beschreibung des Feldes, die zweite das Input-Element und die Dritte ist für die Anzeige von Fehlern zuständig, zu Beginn aber leer!

Der jQuery Part

So weit so gut, nun haben wir eigentlich schon alles was wir benötigen, und wenn wir nun nicht die Absicht hätten JavaScript zu benutzen wären wir an dieser Stelle schon fertig, müssten nur noch den Controller Part implementieren und könnten alles zu den Akten legen. Aber wir wollen dem Benutzer hier eine möglichsts angenehme Erfahrung bieten, denn vielleicht habt ihr es schon selbst erlebt und musstet euch auf einer Seite anmelden wo die Anmeldung ein Krampf war, das kann einem schon mal den einen oder anderen User kosten!

Was wollen wir hier nun also verbessern?

  • Wenn der Benutzer einen Benutzernamen eingibt prüft das System im Hintergrund automatisch ob dieser Name schon vergeben ist und markiert das Eingabe Feld entsprechend.
  • Nach der Eingabe der Email-Adresse wird diese automatisch geprüft nach Format und Verfügbarkeit und der Benutzer bekommt signalisiert ob damit alles in Ordnung ist, natürlich alles im Hintergrund
  • Wenn der Benutzer sein Passwort wählt prüften wir ob dessen Stärke für uns ausreicht und ob beide Passwortfelder auch das gleiche Passwort beinhalten
  • Der Absenden-Button wird erst anklickbar, nachdem alle Felder so ausgefüllt sind wie wir es uns vorstellen

Alles das können wir dank jQuery sehr einfach erreichen. Fangen wir mal vorne mit Punkt 1 an.

Erst ein mal zu dem allgemeinen Ablauf, wie soll das Ganze funktionieren?

  1. Also der Benutzer tippt seinen Wunschnamen ein,
  2. und wechselt aus dem Benutzername-Eingabefeld.
  3. Nun soll unsere Webseite den eingegebenen Wert nehmen, und diesen an den Server senden
  4. Der Server prüft den Namen auf Verfügbarkeit oder Form und Verbotene Zeichen etc
  5. Und sendet eine Information zurück. Diese Information ist entweder ein Fehler oder eine Erfolgsmeldung
  6. Je nachdem ob ein Erfolg oder ein Fehler vermeldet wird wird eine Fehlermeldung angezeigt und das Eingabefeld markiert

Klingt doch eigentlich ganz logisch! Fangen wir an. Erst einmal benötigen wir die jQuery Scriptdatei, diese bekommen wir direkt auf der Startseite von www.jquery.com Rechts oben auf der Startseite könnt ihr zwischen der Production und der Development Version wählen. Der unterschied besteht nur darin, dass die Production Version stark komprimiert ist und somit weniger Traffic verursacht, wenn ihr recht frisch seit was jQuery und javascript angeht solltet ihr euch die Development Version laden, da diese besser zu debuggen ist!

Nachdem ihr das Script geladen habt müssen wir das in unser Projekt einbinden. Zieht die js-Datei einfach aus dem Windows Explorer per Drag & Drop in euer Scripts-Ordner im Projekt Explorer. Nun fügen wir noch die Referenz auf die Datei hinzu, das machen wir am besten in der _Layout Datei die im Shared-Verzeichnis des View Verzeichnisses liegt. Hier ist wahrscheinlich schon ein Verweis auf ein jQuery Script vorhanden, ihr müsst nur noch den Pfad anpassen:


<script src="@Url.Content("~/Scripts/jquery.1.5.1.min.js")" type="text/javascript"></script>

Diese _Layout Datei wird automatisch in alle unsere Views eingebunden (zur Laufzeit), deswegen müssen wir den Verweis  nur an dieser Stelle einfügen, praktisch oder?

Nachdem das geschafft ist können wir uns dem eigentlichen Teil widmen. Wechseln wir also wieder zurück zu unserem Login Formular und machen uns an unseren Punkt 1.

Bevor wir starten möchte ich hier nochmal kurz erwähnen, dass das ein Anfänger Tutorial ist und wir die Kommunikation mit dem Server sehr einfach gestalten werden, eventuell werde ich dann noch einen weiteren Teil machen in dem wir die Kommunikation mit JSON realisieren.

Fangen wir an

JQuery ist nichts anderes als Javascript, ihr habt sicherlich auch schon Javascript Dateien erstellt und diese dann in eure Webseiten eingebunden, hier machen wir nichts anderes, ihr könnt ja auch einfach in die jQuery Datei reinschauen, es ist "nur" javascript.

Wenn wir Funktionen von jQuery benutzen wollen können wir das tun in dem wir das Dollarzeichen benutzen "$" oder jQuery ausschreiben, so funktioniert beides:


    $.ajax(...);
    jQuery.ajax(...);

Ich nutze nur die $-Schreibweise, einfach nur weil es kürzer ist, es ist jedoch euch überlassen was ihr lieber mögt.

Mit jQuery ist sehr einfach Seitenelemente im DOM auszuwählen, so genügt eine einfache Angabe der Klasse, ID oder des Elementen-Typs um diese auszuwählen. Hier ein paar Beispiele:


<script type="text/javascript">
    //Wählt das Element mit der ID username aus und setzt die Hintergrundfarbe auf rot
    $('#username').css('background-color', 'red');

    //Wählt ALLE Elemente mit der Klasse link aus und setzt die Hintergrundfarbe auf rot
    $('.link').css('background-color', 'red');

    //Wählt ALLE Input-Elemente aus und setzt deren Hintergrundfarbe auf rot
    $('input').css('background-color', 'red');
</script>

Das obere Beispiel zeigt wie wir mit mir einer Zeile eine ganze menge Elemente bearbeiten können, die ganze Arbeit erledigt jQuery für uns im Hintergrund. Hier habe ich jQuerys methode "css" benutzt, diese erlaubt es uns eine bestimmte CSS-Eigenschaft eines Elements zu setzten oder zu bearbeiten.

Das ist eigentlich schon das Grundkonzept von jQuery, man wählt sich die Elemente aus mit denen man etwas anstellen will und führt einige Modifikationen an ihnen durch.

Weiterhin bietet uns jQuery auch die Möglichkeit Events anzulegen und zu behandeln, was für uns in Hinsicht auf unsere Aufgaben gleich noch wichtig wird. Aber zunächst ein kleines Beispiel:


$('.my_button').click(function () {
	$('.my_button').toggleClass('some_css_class');
});

Dieser Dreizeiler hat es schon ganz schön in sich, denn hier geschieht eine ganze Menge. Als erstes suchen wir uns das Element mit der Klasse my_button und fügen diesem mit der Click-Methode ein Click-Event hinzu. Als Parameter übergeben wir hier auch gleich die Methode, die ausgeführt werden soll, wenn der Benutzer auf dieses Element klickt.

Innerhalb der Methode wählen wir dann dieses Element erneut aus und ändern dessen Klasse mit der toggleClass Methode. Diese Methode hat aber eine Sonderheit, nämlich dass sie sich merkt welche Klasse diesem Element zugewiesen war bevor darauf geklickt wurde, so wird bei einem erneuten Klick die Klasse wieder zurückgetauscht zu der ersten Klasse.

Das ändern der Klassen von Elementen ist sehr wichtig, denn so kann man sehr einfach das Aussehen von diesen ändern. Wenn der Benutzer seinen Namen eingegeben hat soll er Feedback bekommen ob dieser Name ok ist, das soll so realisiert werden:

Ablauf der Visualisierung

Eingabe -> Überprüfung (Auf dem Server) -> Anzeige des Ergebnisses. Dank der kleinen Icons im Textfeld weiß der Benutzer sofort wie es um seinen Namen steht und er kann auch erkennen, dass die Webseite gerade beschäftigt ist durch den kleinen Kreisel in Schritt 2. Und falls es nicht klappt weiß der Benutzer sofort woran es gelegen hat, da er eine genaue Fehlermeldung bekommt. Und das alles geschieht ohne die Seite neuladen zu müssen nebenbei.

Das Nachladen der benötigten Informationen im Hintergrund nennt man Ajax, dabei ist das keine neue Technologie, sondern einfach nur eine Art einen Request im Hintergrund über JavaScript abzusetzen.

Da wir oben bereits unser Formular angefertigt haben, über das der Benutzer sich registrieren soll können wir uns nun etwas um die Serverseite kümmern und erstellen die nötigen Actions in dem Validation Controller der für die Überprüfung der Vom Benutzer eingegebenen Werte zuständig sein wird:


public class ValidationController : Controller
{
    //
    // GET: /Validation/CheckUsername/[name]

    public String CheckUsername(string username)
    {
        //Wenn in unserer "Datenbank" der Name bei einem anderen Benutzer Auftaucht
        if (new UserDatabase().Users.Where(u => u.Username.Equals(username)).ToList().Count > 0) {
            //Eine Fehlermeldung zurückgeben
            return "Dieser Benutzername ist schon vergeben";
        }

        //Wenn der Benutzername kürzer als 5 Zeichen ist ebenfalls Fehler ausgeben
        if(username.Length < 5){
            return "Der Benutzername ist zu Kurz!";
        }

        //Falls es nichts zu meckern gibt geben wir "ok" aus
        return "ok";
    }
}

In diesem Controller habe ich eine Action Methode definiert, die einen string zurück gibt statt einem ActionResult, dadurch wird der Text den wir im Returnstatement abgeben direkt an den Browser weitergereicht ohne Umweg über eine View die wir uns dadurch sparen.
Die Methode selbst macht nichts spannendes, zu erst wird hier die UserDatabase nach Usern durchsucht die den selben Namen haben und bei einem Treffer eine Fehlermeldung ausgegeben und als zweites führe ich eine Prüfung darauf durch ob der Benutzername zu kurz ist. - Falls alle Kriterien passen geben wir ein "ok" zurück.
Die UserDatabase Klasse ist übrigens nur ein Dummy Repository, dass für uns eine Datenbank simuliert:


public class UserDatabase {

    public List Users;

    public UserDatabase() {
        Users = new List(){
            new User(){Username = "Bernd", Useremail = "bernd@gmx.de"},
            new User(){Username = "Bill", Useremail = "bill@microsoft.de"}
        };
    }
}
public class User {
    public string Username { get; set; }
    public string Useremail { get; set; }
}

Nun haben wir eine sehr simple Überprüfung des Benutzernamen eingebaut. Machen wir das gleich noch mal für die Email Adresse und das Passwort:


public string CheckEmail(string email) {
    //Wenn in unserer "Datenbank" die Emailadresse bei einem anderen Benutzer Auftaucht
    if (new UserDatabase().Users.Where(u => u.Useremail.Equals(email)).ToList().Count > 0) {
        //Eine Fehlermeldung zurückgeben
        return "Diese Emialadresse ist schon vergeben";
    }

    return "ok";
}

public string CheckPassword(string password) {
    //Unser einziges Kriterium für das Passwort ist dass es mindestens 4 Zeichen lang sein muss
    if (password.Length < 4) {
        return "Das Passwort ist zu kurz!";
    }

    return "ok";
}

Absolut nichts kompliziertes wie ihr seht. Natürlich halte ich hier die Methoden und Aktionen sehr simpel um dies verständlicher zu machen, in einem echten Projekt würde man hier natürlich anders vorgehen. Das werden wir dann im zweiten Teil besprechen.

Da unser Backend nun bereit ist müssen wir uns jQuery kümmern und unserem Formular beibringen im Hintergrund mit dem Server zu kommunizieren.


$(document).ready(function () {

    $('#UserName').change(function () {
        //Diese Aktion wird ausgeführt wenn sich der Test im Username
        //Textfeld ändert

        //Style klassen entfernen und die validierungsklasse einfügen
        $('#UserName').removeClass('validation_ok validation_error');
        $('#UserName').addClass('validating');

        var username = $('#UserName').val();
        $.ajax({ url: '/Validation/CheckUserName/' + username,
            success: function (data) {
                if (data == "ok") {
                    //Die Daten wurden vom Controller akzeptiert
                    $('#UserName').removeClass('validating');
                    $('#UserName').addClass('validation_ok');
                    $('#UserName_error').html('');
                } else {
                    //Fehlermeldung vom Server ausgeben
                    $('#UserName').removeClass('validating');
                    $('#UserName').addClass('validation_error');
                    $('#UserName_error').html(data);
                }
            }
        });
    });
});

Gehen wir den Code mal gemeinsam durch, wir beginnen mit der jQuery Funktion "ready", diese wird automatisch ausgeführt sobald der Browser die komplette Seite geladen hat. Als Parameter übergeben wir eine anonyme Funktion, die daraufhin direkt ausgeführt wird.

Innerhalb dieser Funktion (Zeile 3) benutzen wir die jQuery Selektoren um die Textbox mit der id "UserName" zu schnappen und hängen dieser ein "change" Event an. Dieses Event wird immer ausgeführt wenn sich der Inhalt der Textbox ändert. An dieser Stelle wollen wir eingreifen und die geänderten Daten zum Server senden, damit er diese prüfen kann.

In Zeile 8 und 9 benutzen wir die "removeClass" und "addClass" Funktionen von jQuery um der "UserName" Textbox CSS Klassen hinzuzufügen oder wegzunehmen. So fügen wir in Zeile 9 die CSS Klasse hinzu, durch die die TextBox das Animations-GIF erhält, das dem Benutzer anzeigt, dass die Eingaben überprüft werden.

Der Spannende Teil beginnt erst in Zeile 11, denn hier lesen wir den Benutzernamen aus der Textbox und senden diesen dann über die "ajax" Methode von jQuery zum Server. Diese Methode von jQuery ist sehr mächtig und man kann hier dementsprechend diverse Parameter definieren, aber wir benutzen hier stattdessen nur die einfachste Variante, und diese benötigt nur die URL an die der Request gesendet werden soll und eine Referenz auf eine Funktion die ausgeführt werden soll wenn alles erfolgreich verlaufen ist.

Die URL selbst haben wir durch die Namen unserer Controller im Backend schon vergeben, denn wir sprechen hier den Validation-Controller an und rufen die CheckUserName-Methode auf, der wir den eingelesenen Namen als Parameter übergeben. Heraus kommt eine URL wie z.B. diese hier: localhost/Validation/CheckUserName/Bill.

Nachdem der Request nun angesendet wurde und erfolgreich eine Antwort empfangen wurde, wird unsere anonyme Funktion ausgeführt, die das vom Server zurückgegebene Ergebnis auswertet. Im Fall dass der Server ein "ok" zurückgibt wird ein grüner Haken im Textfeld angezeigt und ansonsten ein rotes "x" und die Fehlermeldung in nebenstehenden span ausgegeben. (Zeile 23)

Schauen wir uns doch mal an ob alles so funktioniert wie geplant:

Notiz des Autors: Bei dieser Abbildung wurde kein Wert auf optische Schönheit gelegt

Wie man sieht wurde der Benutzername "Bernd" als fehlerhaft markiert, da dieser bereits in unserer "Datenbank" auftaucht, die Emailadresse hingegen ist ok, da sie noch nicht benutzt wird.

Die jQuery Implementierung für die restlichen  Textfelder kann eigentlich 1 zu 1 übernommen werden, es sollten lediglich die Parameter ausgetauscht werden. Die einzige kleine Besonderheit stellt die Prüfung des Passworts dar, ob die beiden Felder gleich sind, das kann man nämlich komplett clientseitig regeln, ohne die Daten zum Server zu senden:


$('#UserPass2').change(function () {
    //Diese Aktion wird ausgeführt wenn sich der Text im Passwort
    //Textfeld ändert

    //Style klassen entfernen
    $('#UserPass2').removeClass('validation_ok validation_error');

    var pass = $('#UserPass').val();
    var pass2 = $('#UserPass2').val();

    if (pass == pass2) {
        //Die Daten wurden vom Controller akzeptiert
        $('#UserPass2').addClass('validation_ok');
        $('#UserPass2_error').html('');
    } else {
        //Fehlermeldung ausgeben
        $('#UserPass2').addClass('validation_error');
        $('#UserPass2_error').html('Die Passwörter sind nicht gleich');
    }
});

Im Grunde sind wir nun fertig und haben auf einfachste Weise unser Registrierungsformular aufgewertet und dem User vielleicht ein paar Nerven gespart.

Ich möchte hier noch mal hinweisen, dass man in einem Realprojekt nicht so handeln würde, da es viel zu umständlich und nicht wirklich gut wartbar ist. Dieser Beitrag soll lediglich die Grundlagen erklären und zeigen wie man so etwas zu Fuß und mit den grundlegendsten Mitteln erstellen kann.

Im nächsten Teil werden wir dann die MVC3 eigenen Features benutzen die uns diese Aufgaben um einiges erleichtern und zu einem Großteil automatisch funktionieren.

Das Demo-Projekt könnt ihr hier laden: Download [VS2010 c#]

Teil 2 lesen >>
kick it on dotnet-kicks.de

10Jan/110

.NET WebServices anlegen und konsumieren

Letzte Woche haben uns angeschaut, wie man unter Java einen WebService anlegen kann und diesen dann auch verwenden (konsumieren), heute gucken wir wie das Ganze unter .NET funktioniert und legen den selben Service auch hier mal an.

HINWEIS: Ich verwende hier Visual Studio 2010 Ultimate, soweit ich weiß können die C#/VB.NET Express Versionen keine WebServices anlegen, dazu solltet ihr den Visual Web Developer Express herunterladen.

Klickt also auf Datei>Neu> Projekt und Wählt "Web" bzw. "Internet" unter C#. Damit euch das WebService Projekt überhaupt vorgeschlagen wird müsst ihr die verwendete Frameworkversion auf 2.0 stellen (Siehe Bild), wählt dann ASP.NET Webdienstanwendung. Benennt das Projekt nun "USerDB" (genauso wie im Java Beispiel) und klickt auf OK.

Wenn das Projekt angelegt ist, solltet ihr ungefähr folgendes sehen:

Im Grunde haben wir hier bereits einen funktionierenden WebService den wir auch schon ausführen können. Ähnlich wie beim Glassfish unter Java bekommen wir dann eine Testseite angezeigt auf der alle Methoden des Dienstes sichtbar sind und getestet werden können:

Bevor wir hier aber weiter machen implementieren wir erst einmal unsere Methode aus dem Java Beispiel:

Wenn wir den Service erneut ausführen und auf der Testseite unsere Funktion wählen bekommen wir ein ähnliches Bild zu sehen wie unter Java:

Auch hier wird anschließend ein SOAP Request für uns erzeugt und an den Service gesendet, dieser wird dann inklusive dem SOAP Response auf der Ergebnisseite angezeigt.

Damit haben wir den WebService bereits fertiggestellt, machen wir uns nun also daran diesen zu konsumieren.

Fügen wir als erstes ein neues Konsolen Projekt zu unserer Projektmappe hinzu (Bild 6). Nachdem das Projekt angelegt ist fügen wir einen neuen Webverweis hinzu (Bild 7). In dem Dialog der nun auftaucht kann man die Quelle für die Schnittstellenbeschreibung (WSDL) wählen. Man kann hier direkt eine Referenz auf das Projekt in der Projektmappe anlegen. Wir wollen aber direkt die URL der WSDL in der Obere Textfeld angeben.

An die WSDL kommt man übrigens sehr einfach, indem man die Testerseite des WebServices aufruft und dort auf den Link namens "Dienstbeschreibung" klickt, diese URL müssen wir hier angeben. Das Tool analysiert die WSDL und zeigt uns eine Übersicht über die Operationen dieses Dienstes an (Bild 8), hier tragen wir noch den gewünschten Namen ein (bei mir "UserDBService") und klicken auf Verweis hinzufügen.

An dieser Stelle hat die IDE für uns den harten Teil schon erledigt und alle nötigen Klassen und Methoden generiert, die nötig sind um unseren WebService zu nutzen. Implementieren wir also unsere Funktion aus dem letzten Artikel:

Die interessanten Stellen habe ich hier markiert, so sollte man nicht vergessen eine Referenz auf unseren WebService zu setzen bevor man loslegt.

Im Vergleich zu Java bekommen wir hier sogar noch mehr fürs Geld, denn in den generierten Klasse finden wir zu unseren Methoden auch schon asynchrone Aufrufe inklusive der Completed-Events:

Und da die Klasse von System.Web.Services.Protocols.SoapHttpClientProtocol erbt, bekommen wir auch alle anderen wichtigen Properties und Funktionen die man in einem web-bezogenen Projekt benötigen könnte :)

Die generierten Klassen und auch die WSDL findet ihr übrigens im Projektverzeichnis in dem Ordner "Web References".

Führen wir nun unser Programm aus, erwartet uns das Selbe wie in unserem Java Beispiel:

Natürlich muss der Dienst nicht unbedingt in .NET sein, so könntet ihr genauso gut die WSDL aus unserem Java Beispiel verwenden um einen .NET Consumer für einen Java WebService zu erstellen .

kick it on dotnet-kicks.de

5Jan/113

Unbegrenzte Anzahl an Parametern uebergeben

Mir ist aufgefallen, dass viele gar nicht wissen, dass man Methoden so gestalten kann, dass diese eine unbestimmte menge an Parametern akzeptieren. Das gibt es sowohl in Java als auch in .NET (und wohl jeder anderen höheren Programmiersprache)

Wie sieht das Ganze aus? Naja wenn ihr schon mit C#/.NET Gearbeitet habt werdet ihr wohl nicht um diese Funktion herum gekommen sein:


string var = String.Format("Hallo mein Name ist {0} und ich komme aus {1}", "Bernd", "Kassel");

Die Zahlen in den Geschweiften Klammern sind hierbei Platzhalter, die später über eine Variable gefüllt werden. Von diesen Platzhaltern kann man beliebig viele angeben, dementsprechend müssen dann aber auch genauso viele Parameter mit den Werten angegeben werden.

Wie sieht hier die Deklaration dieser Methode aus?


public void DoSomething(int someValue, params string[] values)
{
    foreach (string value in values){
        Console.WriteLine(value);
	}
}

Diese Methode nimmt nun einen normalen int Parameter an und ab dann können beliebig viele Werte vom Typ String folgen:


DoSomething(12345, "Hallo", "Wer", "Bist", "Du");

Genauso kann man das auch in Java machen, hier ist es sogar etwas schöner gelöst wie ich finde:


//Methoden Deklaration
public DoSomething(int someValue, String... values) {
	for(String vaule : values){
		System.out.println(value);
	}
}

//Nutzung:
DoSomething(12345, "Hallo", "Wer", "Bist", "Du");

In Java werden hier nach dem Variablentyp drei Punkte angehängt die signalisieren, dass dieser Typ nun beliebig oft folgen kann.

Dabei wird intern aber auch nur ein Array mit den Werten erzeugt, das kann man bei der .NET Variante bereits in der Deklaration erkennen. So lässt sich in Java die main-Methode auch so schreiben, ohne dass es zu Problemen kommt:


public static void main(String... args) {
    for(String s : args){
        System.out.println(s);
    }
}

Es sei an dieser Stelle noch erwähnt, dass der Parameter, der beliebig oft folgen kann immer als letztes angegeben werden muss - aus offensichtlichen Gründen ;-)

Diese Schreibweise kann an einigen Stellen für deutlich bessere Lesbarkeit sorgen und vereinfacht einfach nur die Anwendung der Funktionen, sollte man auf jeden Fall schon mal gesehen haben.

21Dez/102

Eine eigene Boolean.ToInt Methode bauen

Lächerlich werden nun sicher alle von euch denken, eine ToInt Methode implementieren, die nichts anderes macht als den boolischen Wert in eine 1 umzuwandeln wenn true oder in eine 0 wenn false.

Im Grunde möchte ich euch hier auch zustimmen, denn das ist alles andere als schwer! Aber C# bietet uns hier viele Möglichkeiten um an unser Ziel zu kommen, deswegen habe ich mir gedacht schreibe ich es mal nieder.

Der Einfachste Ansatz ist sicherlich wie folgt:


public int ToInt(bool wert) {
    if (wert) {
        return 1;
    } else {
        return 0;
    }
}

Diese Funktion arbeitet natürlich tadellos und erfüllt ihren Zweck zu 100%. Aber es geht noch schöner und eleganter wie ich finde. So kann man sich die IF-Bedingung sparen und das Ganze etwas abkürzen:


public int ToInt(bool wert) {
    return Convert.ToInt32(wert);
}

Sehr schön, mehrere Zeilen gespart und das Ergebnis ist immer noch das Selbe! Doch das geht noch weiter, man kann sogar hier noch was einsparen, in dem man die tollen Features von C# nutzt:


public int ToInt(bool wert) {
   return wert ? 1 : 0;
}

Falls euch die Syntax nichts sagt, wir nutzen hier den "Conditional Operator", der übrigens schon sehr lange existiert. Zu lesen wäre diese Zeile wie die IF-Bedingung aus dem ernsten Versuch. Wenn die Bedingung vor dem Fragezeichen erfüllt (true) ist dann soll die 1 zurückgegeben werden ansonsten die 0.

Ich finde diese Syntax lässt sich sehr gut lesen, und da ein Boolischer Wert nicht null sein kann laufen wir hier auch nicht Gefahr eine Exception auszulösen. Wenn wir das Ganze noch in eine Extension Method packen können wir das auch sehr bequem benutzen:


public static class Class1 {
    public static int ToInt(this bool wert) {
        return wert ? 1 : 0;
    }

    public static bool ToBool(this int wert) {
        return wert == 1 ? true : false;
    }

    public static void main() {
        bool var = true;

        if (var.ToInt() == 1) {
            //...
        }

        int var2 = 1;

        bool var3 = var2.ToBool();
    }
}
Ich habe hier auch den umgekehrten Weg mit aufgenommen (IntToBool), hier sollte man vielleicht noch erwähnen, dass nur bei einer 1 true zurückgegeben wird, ansonsten wird false abgeliefert egal welchen int Wert man übergibt!
Wie gesagt, das ist nichts Weltbewegendes, aber ich bin nicht gleich drauf gekommen den Conditional Operator hier zu verwenden daher der Blogpost und vielleicht bringt es ja den einen oder anderen von euch auf tolle Gedanken ;-) 

7Dez/104

C#: Threads mit Parametern Starten

Wenn ihr auch mal mit Threads gearbeitet habt habt ihr sicherlich auch schon festgestellt, dass es zu Problemen kommt, wenn man einen Thread starten möchte und diesem auch noch Parameter unterjubeln will.

Ein normaler(einfacher) Threadstart sieht ja folgendermaßen aus:


public class test {
    public test() {
        Auto a = new Auto();

        Thread t = new Thread(new ThreadStart(a.Fahre));
    }
}

public class Auto {
    public void Fahre(){
        //...
    }
}

Aber was ist wenn wir nun dem Auto auch sagen sollen wie weit es fahren soll? Also so:


public class test {
    public test() {
        Auto a = new Auto();

        Thread t = new Thread(new ThreadStart(a.Fahre(100)));
    }
}

public class Auto {
    public void Fahre(){
        //...
    }

    public void Fahre(int wieWeit) {
        //...
    }
}

Leider geht das nicht so einfach, da ThreadStart einen Methodennamen erwartet. Hier müssen wir also anders ansetzen. Eine Möglichkeit dieses Problem zu lösen bzw. zu umgehen ist es die Klasse Auto etwas zu modifizieren und die Parameter, die wir eigentlich über den Methodenaufruf übergeben wollten über den Konstruktor zu übergeben (oder über Properties zu setzen). Somit wäre die Fahre Methode wieder frei von Parametern und könnte problemlos über ThreadStart aufgerufen werden:


public class test {
    public test() {
        Auto a = new Auto(100);

        Thread t = new Thread(new ThreadStart(a.Fahre));
    }
}

public class Auto {
    private int wieWeit;

    public Auto(int wieWeit) {
        this.wieWeit = wieWeit;
    }

    public void Fahre(){
        //... hier kann man mit dem Wert
        // von wieWeit arbeiten
    }
}

Aber diese "Lösung" ist natürlich auch nicht das Gelbe vom Ei. Deswegen habe ich noch ein wenig gegoogelt und habe eine sehr schöne und zugleich einfache Lösung entdeckt:


    public class test {
        public test() {
            Auto a = new Auto();

            ThreadStart start = delegate { a.Fahre(100); };
            Thread t = new Thread(new ThreadStart(start));
        }
    }

    public class Auto {

        public void Fahre(int wieWeit) {
            //...
        }
    }

Hier machen wir von den Anonymen Methoden Gebrauch (siehe Zeile 5) und packen die in ein Delegate, das wir dann dem ThreadStart übergeben. Hier können wir auch bequem unseren Parameter mit angeben und müssen somit auch nicht an der Klasse selbst Änderungen vornehmen.

Kleiner Nachtrag noch:
Maximilian hat mich grad noch an das ParameterizedThreadStart Delegate aufmerksam gemacht, das habe ich noch unbewusst ausgelassen :) . Dieses bietet ebenfalls eine angenehme Möglichkeit Parameter an Threads zu übergeben, hier auch dazu ein kleines Beispiel:


public class test {
    public test() {
        Auto a = new Auto();

        Thread t = new Thread(new ParameterizedThreadStart(a.Fahre));
        t.Start(100);
    }
}

public class Auto {

    public  void Fahre(object wieWeit) {
        //...
    }
}

Man beachte hierbei, dass der Typ des Parameters nun Object ist (Zeile 12) deswegen muss vor der Verwendung noch ein Cast stattfinden. Außerdem könnte man Probleme bekommen, wenn man Überladungen benutzen will.

Das ganze ist natürlich nichts weltbewegendes, aber da ich es noch nicht kannte habe ich es hier mal mit aufgenommen.
kick it on dotnet-kicks.de

24Nov/101

C#: ++/– Operator auf eigene Klassen anwenden

Ihr habt den ++/-- (inkrement/dekrement) Operator bestimmt schon tausende Male eingesetzt ohne viel darüber nachzudenken, genau wie ich, doch heute ist mir schlagartig bewusst geworden, dass dieser Operator auch ein paar von meinen Klassen gut stehen würde und die Anwendung und die Lesbarkeit des Codes verbessern würde.

Die Umsetzung gestaltet sich hier zum Glück sehr einfach:


class Program {
    static void Main(string[] args) {

        Person a = new Person("Alf", 10);

        ++a;

        Console.WriteLine(a.ToString());    //Ausgabe: Alf - 11

        a++;

        Console.WriteLine(a.ToString());    //Ausgabe: Alf - 12

        a--;

        Console.WriteLine(a.ToString());    //Ausgabe: Alf - 11

        --a;

        Console.WriteLine(a.ToString());    //Ausgabe: Alf - 10

        Console.ReadLine();
    }
}

public class Person {
    int Alter { get; set; }
    string Name { get; set; }

    public Person(string Name, int Alter) {
        this.Alter = Alter;
        this.Name = Name;
    }

    public static Person operator ++(Person p){
        p.Alter++;
        return p;
    }

    public static Person operator --(Person p) {
        p.Alter--;
        return p;
    }

    public override string ToString(){
        return this.Name + " - " + this.Alter.ToString();
    }
}

Es muss lediglich eine statische Methode in die Klasse eingebunden werden, deren Rückgabewert ebenfalls der Klassentyp ist. Desweiteren folgt vor dem Namen der Funktion das Stichwort "operator" und es muss auch noch ein Parameter vom Typ der Klasse übergeben werden.

Innerhalb dieser Methode können wir nun entscheiden, was passieren soll wenn der Operator benutzt wird. In meinem Fall habe ich mich dazu entschieden, das Alter der Person um eins zu erhöhen, aber der Fantasie sind hier natürlich keine Grenzen gesetzt.

Natürlich kann man auch weitere Operatoren auf diese Weise implementieren, wie zum Beispiel den +/- (Plus/Minus) Operator, dazu gibt es ein nettes Beispiel im MSDN.

Eine feine Sache wie ich finde, nicht kompliziert - kann aber helfen den Code verständlicher und einfacher zu gestalten.

12Nov/101

ASP.NET MVC3: Remote Attribut “richtig” nutzen

Seit gestern probiere ich die neuen Attribute in dem ASP.NET MVC3 RC aus und bin eigentlich sehr zufrieden. Nur ein Attribut wollte bisher einfach nicht funktionieren, nämlich das Remote-Attribut.

In den offiziellen Release Notes ist dieses Attribut beschrieben und es wird folgendes Beispiel benutzt um es dem Leser näher zubringen:

image

Dies habe ich auch als Vorlage genommen und meine Methode im Controller implementiert:

image

Doch das hat nicht funktioniert. Nun weiß ich auch wieso, denn hier wird ein falsches Ergebnis zurück gesendet. Das Ergebnis dieser Methode liefert ein “False” oder “True” ab, mit einem großen Buchstaben am Anfang – und das macht uns alles kaputt!

Hier ist unser Request den jQuery für uns erzeugt:

image

Dieser Request kommt erfolgreich auf dem Server an und wird korrekt verarbeitet. Als Response kommt dann folgendes zurück:

image

Man beachte hier das großgeschriebene “False”. Also arbeitet der Controller völlig korrekt, nur müsste er ein kleines “false” zurückgeben.

Nun wenn man es Quick & Dirty haben will kann man einfach einen String zurückgeben:

image

Der bessere Weg wäre wohl ein JSON Result:

image

Nun funktioniert auch alles wie es soll und ich kann ruhig schlafen Smiley

Get Adobe Flash playerPlugin by wpburn.com wordpress themes