BigBastis Blog About Me & my Digital Lifestyle

4Jul/1193

Google Plus Ersteindruck und Einladungen

Diese Woche kommt man ja an keiner Newsseite mehr vorbei ohne von Google Plus zu lesen. Ich habe dort inzwischen auch einen Account und kann die allgemeine Begeisterung tatsächlich teilen.

Bisher sind alle Features gut geordnet und leicht verständlich. Vorallem die Circles mit denen man seine Bekannten in Grüppchen unterteilt und somit genau kontrollieren kann wer Zugriff auf die Daten und Inhalte hat die man veröffentlicht sind sehr gut gelößt - da kann sich Facebook eine Scheibe abschneiden.

Da ich eh kein Facebook Freund bin freut es mich natürlich umsomehr dass Google nun eine Eigeninitiative gestartet hat und im Vergleich zu Buzz oder Wave ist das Konzept diemal durchdacht und darauf angesetzt die Schwächen der anderen Dienste auszunutzen.

Braucht Ihr noch Einladungen?

Wenn ihr noch eine Einladung zu Google+ braucht schreibt einfach ein Kommentar und füllt das E-Mail Feld aus, im Text Selbst braucht ihr die Email nicht zu erwähnen. Die angegebene Adresse sollte hierbei von Google sein, da es sonst nicht klappt.

Was zu tun nach der Einladung?

Das Einladungssystem ist momentan ausgeschaltet, deswegen kann man nur über einen kleinen Umweg Luete "Einladen". Nachdem ich euch eingeladen habe, bekommt ihr entweder eine Mail mit einem Link durch den ihr zu einer Seite gelangt wo ihr einen "Mitmachen" Knopf klicken könnt, oder es passiert einfach nichts. Wenn ihr keine Mail bekommt schaut alle paar Minuten auf https://plus.google.com vorbei, es sollte dann automatisch ein Mitmach-Button auftauchen.
Wenn das auch nicht hilft heißt es nur warten ;-)

Update: Laut dem letzten Tweet von Google ist die Anmeldung zu Google Plus nun wieder offen, einfach auf plus.google.com gehen und registrieren :)

Update 2: Doch nicht ;)

8Jun/110

Entstehung einer ASP.NET Webanwendung anhand eines Beispiels

Mit diesem Artikel will ich skizzieren wie eine Webanwendung mittels ASP.NET entworfen und umgesetzt wird. Ich will einen Einblick in die Vorüberlegungen, sowie in die Umsetzung des Projektes geben. Nicht mehr, aber auch nicht weniger.

Vorüberlegungen

Wie fast alle Hobbyprogrammierer erstelle auch ich eine Unzahl unnötiger und zum Teil auch unsinniger Anwendungen. Dies ist der Luxus den man sich leisten kann, wenn man damit nicht sein Geld verdienen muss.

Da ich ab und zu auf Dienstreise gehe, ist die aktuelle Uhrzeit am gegenwärtigen Standort immer ein Thema. Oft kommt auch die Frage auf, wie spät es denn bei den Lieben zu Hause wohl sein mag.

Hierfür  kommt natürlich nur, mein neuestes Steckenpferd, eine Webanwendung in Frage.

Die ersten Überlegungen:

  1. Welcher Aufbau einer Webanwendung ist der beste
  2. Wie ermittle ich meinen aktuellen Standort
  3. Welche zusätzlichen Informationen kann ich noch anzeigen

1. Welcher Aufbau einer Webanwendung ist der beste?

Ich hab mich hier, sehr schnell, für eine Webanwendung entschieden, die ihre Informationen aus einem RSS-Feed bezieht. Vorteil hierbei, es handelt sich um ein XML-Format, welches leicht zu lesen ist und auch anderweitig verwendet werden kann.
Eine Windows-, Linux-, MacOS- oder Android Anwendung könnte den RSS-Feed ebenfalls nutzen.

2. Wie ermittle ich meinen aktuellen Standort

Im Prinzip wäre GPS das ideale Werkzeug um den aktuellen Standort auf der Welt bestimmen zu können. Da ich jedoch nur ein Notebook auf meinen Dienstreisen zur Verfügung habe, fällt das mit dem GPS aus, denn die wenigsten Notebooks verfügen über GPS – meines schon gar nicht.

Eine weitere Möglichkeit meinen Standort zu bestimmen wäre über die IP Adresse, mit der sich mein Computer über den jeweiligen Provider mit dem Internet verbindet. Nicht sehr genau, aber wenn es um die Zeitzone geht – genau genug.

Eine andere Alternative, die mir erst vor kurzem bekannt wurde, ist die Ermittlung des Standortes via HTML 5 – Voraussetzung hierfür sind ein Browser der diese neue Technologie unterstützt und aktiviertes JavaScript.

Die Umsetzung via HTML 5 ist zudem genauer als der Weg über die IP-Adresse. Ideal wäre also die Verknüpfung beider Techniken.

Da meine Seite aktuell mit der IP-Adresse arbeitet, möchte ich das als Basis der folgenden Abhandlungen nehmen.

3. Welche zusätzlichen Informationen kann ich noch anzeigen

Weitere Informationen bietet ASP.NET von allein. IP-Adresse, Sprache, Browser, Auflösung usw.

 

Die Umsetzung:

Wie schon erwähnt ist ein RSS-Feed nichts anderes als eine XML Datei. Diese wird als Antwort (Response) auf eine Anfrage (Request) vom Webservice zurückgegeben.

Im Prinzip also recht einfach

  1. Daten ermitteln
  2. XML erstellen
  3. Daten zurückgeben

Überlegung:

Welche Daten benötigen wir und welche Daten soll der RSS-Feed zusätzlich enthalten?

Im Prinzip benötigen wir nur drei Werte um die aktuelle Uhrzeit und Zeitzone übermitteln zu können.

  1. Die Zeitzone als ID – damit kann dann ganz einfach die passende Zeitzone auf dem Windows-PC gefunden werden.
    (Wie das auf einem MAC OS oder einem Linux Rechner umgesetzt werden kann wäre eine weitere Überlegung wert)
  2. Die Zeitverschiebung in Stunden (Als Basis gilt hier immer die koordinierte Weltzeit)
  3. Die Zeitverschiebung in Minuten (Als Basis gilt hier immer die koordinierte Weltzeit)

 

Alle weiteren Daten sind Beiwerk und blähen unseren RSS-Feed nur auf. Aber wer kommt denn schon ohne Beiwerk aus?

Interessant sind natürlich auch

  1. Die momentane IP-Adresse
  2. Die eingestellte Sprache
  3. Der aktuelle Ort (Stadt) bzw. das Land
  4. Die Region (hier kommen wir später darauf zurück)
  5. Die Geokoordinaten (geographische Länge und Breite)

Umsetzung:

Die erste Schwierigkeit besteht darin aus der IP-Adresse den aktuellen Standort zu ermitteln.

Hierfür gibt es eine Menge Webservices, die aber alle nicht sehr aktuell sind und ihre Daten nicht so einfach zur Verfügung stellen wollen.

Als die beste aller Möglichkeiten hat sich die MaxMind GeoLight City Datenbank in Verbindung mit dem Google Maps UserControl von SubGurim.net gezeigt.
Nachteil hier – die Datenbank ist 30MB schwer und muss jeden Monat aktualisiert werden, da sich die IP-Adressen ständig ändern. Was soviel heißt wie, je länger der Monat dauert je ungenauer die Angaben.

Abhilfe würde hier die kostenpflichtige Datenbank schaffen – diese ist zwar noch Größer wird aber in einem kürzeren Zyklus aktualisiert. Da ich das Ganze aber nur als Hobby-Projekt umsetzen will, sind mir die Kosten dafür zu hoch.

Die kostenpflichtige Datenbank gibt es ebenfalls hier (GeoCity) und kann natürlich auch mit dem gleichen UserControl betrieben werden.

Ich hab mich für das Binary Format der Datenbank entschieden, da diese Version in Verbindung mit dem SubGurim UserControl sehr schnell ist. Die Zugriffszeiten auf meinen RSS-Feed liegen bei etwa 0.5 Sekunden.

Das SubGurim Control wurde für ASP.NET 2.0 entwickelt, arbeitet aber auch im Framework 4 ohne Probleme.

Bindet man nun alles ein – ein Lesen der Dokumentation hilft wie immer weiter - reduziert sich der Code zur Ermittlung der Geokoordinaten auf


Dim location As Location = GetLocationFromIP(userIP)

Im Prinzip schon fast alles. Nur war es nicht unser Ziel die Geokoordinaten zu ermitteln, wir wollten die Uhrzeit und Zeitzone am aktuellen Standort ermitteln.

Anmerkung:

Die Klasse Location ist hier ein Teil des SubGurim.Net UserControls und enthält neben den GeoKoordinaten auch die ermittelte Stadt, das Land (beides als Klartext) und die Region als Kürzel (z.B. 02 = Bayern, 05 = Hessen).

Da ich für die nächsten Schritte keine weiteren Controls, Dll’s oder anderes frei verfügbares Werkzeug gefunden habe, musste ich die Verknüpfung der Standortdaten zur Zeitzone und das Decodieren des Regionkürzels selbst erledigen.

Überlegung:

Ein jeder Punkt dieser Welt gehört einer bestimmten Zeitzone an. Hier gilt es 3 Fälle zu beachten.

  1. Länder die als Ganzes einer Zeitzone angehören (z.B. Deutschland, Österreich, Schweiz)
  2. Länder die mehreren Zeitzonen angehören (z.B. USA, Russland, Indonesien)
  3. Gebiete die nicht erfasst werden können (Oceane und Wüsten)

1. Länder die als Ganzes einer Zeitzone angehören

Die einfachste Form, die Inhalte der Klasse Location können direkt zur Ermittlung der Zeitzone herangezogen werden.

Vereinfacht: Land = Zeitzone = Zeitverschiebung

2. Länder die mehreren Zeitzonen angehören

Nicht mehr ganz so einfach. Die Zeitzone wird hier anhand des Landes und der Region bestimmt.

Vereinfacht: Land (z.B. USA) - Region (z.B. CA - Kalifornien) = Zeitzone = Zeitverschiebung

Sonderfall: Eine Region enthält mehrere Zeitzonen (z.B. USA/Indiana – Eastern- und Central Time)

Hierfür habe ich noch keine Lösung – mir fehlen die genauen Daten – aber vermutlich wird es dann eine weitere Unterteilung anhand der ermittelten Stadt geben.

Land (z.B. USA) – Region (z.B. IN - Indiana) – Stadt (?) = Zeitzone = Zeitverschiebung

3. Gebiete die nicht erfasst werden können

Da es auf dem Meer oder in der Wüste keinen Provider bzw. keine Empfang gibt, kann dieser Fall ausgeschlossen werden.

Lösung hierfür wäre eine Ermittlung des Standortes via Geokoordinaten (GPS), was im Moment noch nicht umgesetzt wurde.

Die beschriebene Funktionalität hab ich in eine DLL gepackt, das alles beschreiben zu wollen würde hier aber zu weit führen.

Die Punkte 1. und 2. werden komplett durch eine List(of Structure) abgebildet, die alle Länder dieser Welt, inkl. den unter 2. beschriebenen Fällen, enthält.


    Public Structure myTimeZone
        Public Country As String
        Public Region As String
        Public TimeZoneInfo As TimeZoneInfo

        Public Sub New(ByVal c As String, ByVal r As String, ByVal tzi As TimeZoneInfo)
            Country = c
            Region = r
            TimeZoneInfo = tzi
        End Sub
    End Structure

Private mytimezones As New List(Of myTimeZone)

Die Klasse „TimeZoneInfo“ ist schon Bestandteil des Frameworks und bildet die auf dem jeweiligen System installierten Zeitzonen ab.

Die durch das SubGurim.Net UserControl bereitgestellten Informationen (Klasse Location) dienen somit als Filter für die Suche innerhalb der Liste. Die dadurch ermittelten Daten können nun den RSS-Feed füllen.

Erstellen eines RSS-Feeds:

Wie schon erwähnt ist ein RSS-Feed nichts anderes als eine XML-Datei welche durch eine Webseite zurückgegeben wird.

Dies kann auf vielfältige Art und Weiße geschehen.

Anfangs erstellte ich meinen Feed innerhalb einer WebForm (*.aspx). Später jedoch bin ich auf eine Methode gestoßen, die mir eleganter erschien, nämlich das Erstellen eines RSS-Feeds mittels eines „Generic Handlers“ (*.ashx)

Im Prinzip wird nichts anderes gemacht, als den kompletten Feed mittels LINQ zusammenzubauen und am Schluss als Response zurückzugeben.


Dim doc As New XDocument()

Dim rss As New XElement("rss")
rss.Add(New XAttribute("version", "2.0"))

Dim channel As New XElement("channel")
rss.Add(channel)

channel.Add(New XElement("title", "The TimeZoneNotifier RSS-Feed"))
channel.Add(New XElement("link", "http://TimeZoneNotifier.free-file-download.de"))
channel.Add(New XElement("description", "This site detects the timezone you're currently staying in !"))
channel.Add(New XElement("ttl", "60"))

Dim item As New XElement("item")

Channel.Add(item)

item.Add(New XElement("userIP", userIP))
item.Add(New XElement("userBrowser", userBrowser))
item.Add(New XElement("userLanguage", userLanguage))
item.Add(New XElement("userCity", userCity))
item.Add(New XElement("userRegion", userRegion))
item.Add(New XElement("userLongitude", userLongitude))
item.Add(New XElement("userLatitude", userLatitude))
item.Add(New XElement("userTimeOffsetHours", userTimeOffsetHours))
item.Add(New XElement("userTimeOffsetMinutes", userTimeOffsetMinutes))
item.Add(New XElement("CurrentUTCTime", CurrentUTCTime.ToString))
item.Add(New XElement("userTimeZone", userTimeZone))

doc.Add(rss)

(Den RSS-Feed wie er dann ausgegeben wird, sehen Sie am Ende dieses Artikels)

Sind wir erst einmal hier angekommen, wurde die meiste Arbeit schon erledigt. Der Rest besteht nur noch im Anzeigen der ermittelten Daten.

Anzeigen der Daten mittels einer WebForm:

Hier zum Verständnis, noch der Code für die Anzeige der Daten.

Da wir den Feed mittels einer Webanwendung abfragen, sind manche Informationen für den RSS-Feed nicht sichtbar. Bei diesen Daten verwerfen wir die Informationen die der RSS-Feed enthält einfach und füllen die Ausgabe mit den Werten der WebForm.


Protected Sub Page_Load(ByVal sender As Object, _
                    ByVal e As System.EventArgs) Handles Me.Load

if Postback Then
'RSS-Feed holen
    Dim retRss As New Xml.XmlDocument
    retRss.Load("http://timezonenotifier.free-file-download.de/rss.ashx?ip=" & _
                Request.UserHostAddress)
    'IP-Adresse das Feeds stimmt
    Me.LabelIP.Text = retRss.SelectSingleNode("/rss/channel/item/userIP").InnerText
    'Wurde eine nicht gültige IP-Adresse erkannt -> Anzeigen der Daten abbrechen
    If Me.LabelIP.Text = "No valid IP-Adress !!" Then
        Exit Sub
    End If
    'Kein Browser im RSS-Feed vorhanden, da vom Server aus angefragt wird
    Me.LabelBrowser.Text = Request.Browser.Browser
    'Keine Sprache im RSS-Feed vorhanden, da vom Server aus angefragt wird
    Try
        Dim ci As New CultureInfo(Request.UserLanguages(0))
        Me.LabelLanguage.Text = ci.DisplayName
    Catch ex As Exception
        Me.LabelLanguage.Text = "Unknown"
    End Try
    'erkannte Stadt
    Me.LabelCity.Text =
        retRss.SelectSingleNode("/rss/channel/item/userCity").InnerText
    'erkannte Region
    Me.LabelRegion.Text =
        retRss.SelectSingleNode("/rss/channel/item/userRegion").InnerText
    'erkannte Geogr. Länge
    Me.LabelLong.Text =
        retRss.SelectSingleNode("/rss/channel/item/userLongitude").InnerText
    'erkannte Geogr. Breite
    Me.LabelLat.Text =
        retRss.SelectSingleNode("/rss/channel/item/userLatitude").InnerText
    'erkannte Zeitverschiebung
    Dim _offsethours As Integer =
        CInt(retRss.SelectSingleNode("/rss/channel/item/userTimeOffsetHours").InnerText)
    Dim _offsetminutes As Integer =
        CInt(retRss.SelectSingleNode("/rss/channel/item/userTimeOffsetMinutes").InnerText)
    'aktuelle Zeit am Standort berechnen
    Dim tempRSS As String =
        retRss.SelectSingleNode("/rss/channel/item/CurrentUTCTime").InnerText
    Me.LabelCurrentTime.Text =
        CDate(tempRSS).AddHours(_offsethours).AddMinutes(_offsetminutes).ToLongDateString & " - " & CDate(tempRSS).AddHours(_offsethours).AddMinutes(_offsetminutes).ToLongTimeString

    Me.LabelCurrentTimeDiff.Text = _offsethours.ToString & _
        " h " & _offsetminutes.ToString & " min"
    'erkannte Zeitzone
    Me.LabelCurrentTimezone.Text =
        retRss.SelectSingleNode("/rss/channel/item/userTimeZone").InnerText
Else
    'kein Postback
End If
End Sub

Die Ergebnisse meiner Arbeit:

Das oben beschriebene hab ich unter http://timezonenotifier.free-file-download.de als ASP.NET Webseite veröffentlicht.
Den RSS-Feed gibt es unter http://timezonenotifier.free-file-download.de/rss.ashx
RSS-Feed (mein Standort)
<pre>


<rss version="2.0">
    <channel>
        <title>The TimeZoneNotifier RSS-Feed</title>
        <link>http://TimeZoneNotifier.free-file-download.de</link>
        <description>
            This site detects the timezone you're currently staying in !
        </description>
        <ttl>60</ttl>
        <item>
            <userIP>79.249.177.227</userIP>
            <userBrowser>Chrome</userBrowser>
            <userLanguage>Deutsch (Deutschland)</userLanguage>
            <userCity>Mering / Germany</userCity>
            <userRegion>Bayern</userRegion>
            <userLongitude>10,9833</userLongitude>
            <userLatitude>48,2667</userLatitude>
            <userTimeOffsetHours>2</userTimeOffsetHours>
            <userTimeOffsetMinutes>0</userTimeOffsetMinutes>
            <CurrentUTCTime>07.06.2011 09:40:14</CurrentUTCTime>
            <userTimeZone>
                (UTC+01:00) Amsterdam, Berlin, Bern, Rom, Stockholm, Wien
            </userTimeZone>
       </item>
    </channel>
</rss>

Quellen:

http://www.maxmind.com/app/geolitecity
http://de.googlemaps.subgurim.net/
http://lukencode.com/2010/05/19/ip-to-geo-location-in-asp-net-mvc/
http://www.aspcode.net/Creating-an-RSS-feed-for-your-ASPNET-site.aspx

Copyright:

Die Rechte der verwendeten Datenbanken und des UserControls liegt bei den Autoren.

Der angebotene RSS-Feed darf frei verwendet werden – eine Nennung der Quelle des Feeds bzw. der Adresse dieses Artikels wird vorausgesetzt.

Ein Dank geht an Sebastian Gross der mir einige Anregungen gegeben hat.

Dieser Service bleibt kostenlos, die Bedingungen zur Nutzung des RSS-Feed können sich jedoch jederzeit ändern.

Über den Autor

Michael Bernhard
Hobby-Programmierer von VB.NET, C# und ASP.NET Anwendungen. Hauptberuflich als Inbetriebnehmer bei der Böwe Systec GmbH beschäftigt. Vorzeigbare Projekte – TimeZone Notifier und TSV Neusäß Junioren.

kick it on dotnet-kicks.de

10Mai/111

Benutzerregistrierung mit ASP.NET MVC und jQuery Teil 2

Im ersten Teil haben wir die Ajax-Funktionalität mit Hilfe von jQuery “zu Fuß” implementiert und haben nur die einfachsten Mittel verwendet. In diesem zweiten Teil wollen wir das nun mit Hilfe des ASP.NET MVC3 Frameworks implementieren, welches uns einiges an Arbeit abnimmt.

Das schöne an der dritten Version des MVC Frameworks ist, dass Microsoft hier schon einige helfende Elemente zum Validieren von Clientangaben eingebaut hat, die wir oft mit nur einer kleinen Zeile Code oder einem Attribut aktivieren können.

Fangen wir also mit unserem Model an und erweitern es um die neuen Attribute die uns das Framework zur Verfügung stellt:


public class RegisterModel2 {

    [Required(AllowEmptyStrings = false,
                ErrorMessage = "Bitte geben Sie einen Benutzernamen an!")]
    [DisplayName("Benutzername")]
    [Remote("ValidateUsername", "Validation")]
    public String UserName { get; set; }

    [Required(AllowEmptyStrings = false,
                ErrorMessage = "Bitte geben Sie eine Emailadresse an!")]
    [DisplayName("E-Mail Adresse")]
    [Remote("ValidateEmail", "Validation")]
    public String UserMail { get; set; }

    [Required(AllowEmptyStrings = false,
                ErrorMessage = "Bitte geben Sie ein Passwort an!")]
    [DisplayName("Passwort")]
    [DataType(DataType.EmailAddress)]
    [Remote("ValidatePassword", "Validation")]
    public String UserPass { get; set; }

    [Required(AllowEmptyStrings = false,
                ErrorMessage = "Bitte wiederholen Sie ihr Passwort!")]
    [Compare("UserPass", ErrorMessage="Die Passwörter stimmen nicht überein!")]
    [DisplayName("Passwort wiederholen")]
    public String UserPass2 { get; set; }
}

 

Wie man sieht sind nun einige Attribute dazugekommen, die Eigenschaften der Klasse an sich haben sich aber nicht verändert! Aber mal langsam, was bedeuten diese Attribute eigentlich?

  • Required
    • Markiert die Eigenschaft als Pflichtfeld. Durch setzen dieses Attributs wird beim Absenden des Formulars automatisch geprüft ob diesem Feld ein Wert zugewiesen wurde, falls nicht wird eine Fehlermeldung generiert.
    • Durch die Option AllowEmptyStrings = false sorgen wir dafür, dass auch Werte die nur als Leerzeichen bestehen ebenfalls Fehler auslösen.
    • Mit dem Setzen der ErrorMessage Eigenschaft können wir eine Eigene Fehlermeldung definieren, die statt der Standardmeldung angezeigt wird. Lässt man diese Eigenschaft weg wird eine Meldung generiert die ca. so ausschaut: “Das Feld "FELDNAME" ist erforderlich.”
  • DisplayName
    • Dieses Attribut haben wir auch schon in dem Letzten Teil benutzt. Dieses sorgt dafür dass wir den Namen für das Eingabefeld, dass der Benutzer später im Browser zu sehen bekommt bereits im Model definieren können.
  • Remote
    • Durch dieses Attribut definieren wir welche Methode und welcher Controller für das Validieren der Eigenschaft verantwortlich ist. Erst wird die Action und als zweiter Parameter der Controller angegeben. Wenn der Benutzer später Eingaben in das Textfeld tätigt, wird diese Action aufgerufen und der eingegebene Wert als Parameter übergeben, sehr ähnlich wie wir es in Teil 1 gemacht haben, aber später mehr dazu.
  • DataType
    • Damit kann man den Inhalt bestimmen was einem beim Validieren helfen kann.
  • Compare
    • Mit diesem Attribut können wir angeben, dass diese Eigenschaft den gleich Wert haben muss wie eine andere. Dies wird dann automatisch von jQuery überprüft, somit müssen wir nicht mehr machen als dieses Attribut zu setzen.
    • Als Parameter übergeben wir den Namen der Eigenschaft mit der der Wert verglichen werden soll und, als zweiten setzen wir eine eigene Fehlermeldung damit eine vernünftige Fehlermeldung angezeigt wird.

Damit haben wir unser Model fertiggestellt, nun schauen wir uns an was wir an unserer View verändern müssen.

Die gute Nachricht ist, dass wir den kompletten JavaScript/jQuery Teil streichen können, da das für uns alles automatisch geregelt wird, so sieht nun unsere View aus:

 


    @using (Html.BeginForm("Submit", "Validation")) {
        <table border="1">
            <tr><td>@Html.LabelFor(model => model.UserName):</td>
                <td>@Html.TextBoxFor(model => model.UserName)</td>
                <td>@Html.ValidationMessageFor(model => model.UserName)</td>
            </tr>
            <tr><td>@Html.LabelFor(model => model.UserMail):</td>
                <td>@Html.TextBoxFor(model => model.UserMail)</td>
                <td>@Html.ValidationMessageFor(model => model.UserMail)</td>
            </tr>
            <tr><td>@Html.LabelFor(model => model.UserPass):</td>
                <td>@Html.TextBoxFor(model => model.UserPass)</td>
                <td>@Html.ValidationMessageFor(model => model.UserPass)</td>
            </tr>
            <tr><td>@Html.LabelFor(model => model.UserPass2):</td>
                <td>@Html.TextBoxFor(model => model.UserPass2)</td>
                <td>@Html.ValidationMessageFor(model => model.UserPass2)</td>
            </tr>
            <tr><td> </td>
                <td><input id="submit_form_button" type="submit"
                            value="Registrierung abschicken" /></td>
                <td> </td>
            </tr>
        </table>
    }

 

Wenn ihr euch den Code anschaut, werdet ihr feststellen, dass sich eigentlich nicht getan hat. Das Einzige was sich verändert hat ist dass nun das Span in dem wir im letzten Teil die Fehler ausgegeben haben verschwunden ist und stattdessen

@Html.ValidationMessageFor(model => model.xxxxx)

aufgetaucht. Wie man sich auch schon von dem Namen ableiten kann wird hier eine Validierungsnachricht angezeigt, also mit anderen Worten die Fehlermeldung die bei der Validierung dieses Feldes entsteht. Diese Fehlermeldungen haben wir zum Teil schon über die Attribute im Model definiert.

Das wars auch schon mit Änderungen. Smiley super oder? Wir haben nun einen Haufen Code rausgeworfen, ein paar Attribute eingefügt und nicht eine Zeile JavaScript geschrieben - perfekt Zwinkerndes Smiley

Aber noch sind wir nicht ganz fertig, denn wir haben nun gar nicht die Regeln für die Validierung des Benutzernamen, der Emailadresse und des Passworts implementiert.

Wenn ihr aufgepasst habt werdet ihr euch daran erinnern, dass wir das Attribut [Remote] verwendet haben und dort als Parameter den Namen einer Action angaben, an die die Informationen zur Validierung gesendet werden sollten.

Diese Actions müssen wir nun natürlich in unserem Validation Controller implementieren, zu unserem Glück unterscheiden sich diese Methoden nur minimal von denen die wir bereits im letzten Teil erstellt haben:


public ActionResult ValidateUsername(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 Json("Dieser Benutzername ist schon vergeben", JsonRequestBehavior.AllowGet);
    }

    //Wenn der Benutzername kürzer als 5 Zeichen ist ebenfalls Fehler ausgeben
    if (UserName == null || UserName.Length < 5) {
        //return "Der Benutzername ist zu Kurz!";
        return Json("Der Benutzername ist zu kurz!", JsonRequestBehavior.AllowGet);
    }

    //Falls es nichts zu meckern gibt geben wir true zurück
    return Json(true, JsonRequestBehavior.AllowGet);
}

 

Was ist passiert? Die Logik der Funktion ist gleich geblieben, lediglich der Rückgabetüp und die Rückgabemethode hat sich geändert. Wir geben nun ein ActionResult statt eines einfachen Strings zurück. Dazu rufen wir die Methode Json auf der wir als Parameter die Daten übergeben die übertragen werden sollen und als zweites erlauben wir GET Aufrufe.

Die Antwort die dadurch erzeugt wird wird automatisch auch in ein Format umgewandelt die jQuery versteht. da wir in diesem Fall aber nur ein Boolean oder einen String übergeben ist dies nicht nötig.

Wenn wir einen String ausgeben wird das als Ausgabe für die Fehlermeldung genutzt. Alternativ können wir auch ein false ausgeben, dann wird die Standardfehlermeldung angezeigt, die nicht allzu schön ist. Durch die Angabe von true sagen teilen wir jQuery auf der Clientseite mit, dass kein Fehler aufgetreten ist und dass es die eventuell angezeigte Fehler ausblenden soll.

Die anderen zwei Validierungsmethoden müssen genauso geändert werden um problemlos mit dem [Remote] Attribut genutzt zu werden wodurch wir den Vorteil erhalten, dass wir kein JavaScript Code schreiben müssen, alles wird von den Frameworks automatisch geregelt.

An dieser Stelle lohnt es sich mal anzuschauen was da eigentlich generiert wird für uns. Starten wir also unsere MVC Applikation und gucken mal in den Quelltext:


<td><label for="UserName">Benutzername</label>:</td>
<td><input data-val="true"
		data-val-remote="&amp;amp;amp;#39;Benutzername&amp;amp;amp;#39; is invalid."
		data-val-remote-additionalfields="*.UserName"
		data-val-remote-url="/Validation/ValidateUsername"
		data-val-required="Das Feld &amp;amp;amp;quot;Benutzername&amp;amp;amp;quot; ist erforderlich."
		id="UserName" name="UserName"
		type="text"
		value="" />
</td>
<td><span class="field-validation-valid"
		data-valmsg-for="UserName"
		data-valmsg-replace="true"></span>
</td>

Oben ist der Ausschnitt zu sehen, der für das Benutzername-Eingabefeld verantwortlich ist inklusive dem dazugehörigen Label und dem Validierungstext.

Auffällig ist, dass kein JavaScript generiert wurde, sondern das Input-Element mit zusätzlichen Tags versehen wurde, die aber nur für jQuery von Bedeutung sind. Andere Applikationen oder Frameworks werden dadurch also nicht beeinflusst, diese ignorieren einfach diese für sie unbekannte Attribute.

Wenn man die Attribute etwas genauer betrachtet wird man einiges aus unserem Model wiederfinden, wie zum Beispiel unsere dort definierte Fehlermeldung.

Nun bleibt nur noch eine Kleinigkeit zu tun, nämlich das nötige CSS zu schreiben dass mit der jQuery Validierung zusammenspielt und die nötigen JavaScript Dateien zu importieren.

Fangen wir mit dem Importieren der JavaScript Bibliotheken an. Wenn ihr ein neues MVC3 Projekt anlegt habt ihr schon alle Dateien die nötig sind bereits in eurem Scriptordner. Öffnet die “_Layout.cshtml” und fügt (falls noch nicht vorhanden) folgende Imports hinzu:


<script src="@Url.Content("~/Scripts/jquery-1.4.1.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

Diese Imports werden nun durch diese Mastervorlage in jede View eingebunden. Natürlich könnt ihr diese Imports auch explizit nur in die View schreiben in der diese auch benötigt werden, das wäre sogar vorteilhafter denke ich.

Zu guter Letzt kümmern wir uns um das CSS. Auch hier generiert euch Visual Studio das nötige CSS wenn ihr ein neues MVC Projekt anlegt, auch wenn ihr als Vorlage ein leeres MVC Projekt wählt. In dem Ordner Content werdet ihr eine Datei namens Site.css finden in der die CSS Klassen für die Validierung stehen:


/* Styles for validation helpers
-----------------------------------------------------------*/
.field-validation-error
{
    color: #ff0000;
}

.field-validation-valid
{
    display: none;
}

.input-validation-error
{
    border: 1px solid #ff0000;
    background-color: #ffeeee;
}

.validation-summary-errors
{
    font-weight: bold;
    color: #ff0000;
}

.validation-summary-valid
{
    display: none;
}

jQuery greift auf diese Klassen zurück um das Aussehen der Eingabefelder entsprechend dem Validierungsergebnis anzupassen. Hier könnt ihr nun eure Eigenen Änderungen vornehmen und die Visualisierung euren Wünschen anpassen.

Ich habe hier noch, um das Beispiel aus Teil 1 nicht aus den Augen zu verlieren die CSS Klasse etwas erweitert um das Aussehen anzugleichen:


.input-validation-error
{
    border: 1px solid #ff0000;
    background-color: #ffeeee;
    background-image: url("../Grafik/cancel.png");
    background-position: right;
    background-repeat: no-repeat;
}

Wenn man die Applikation nun startet funktioniert das Beispiel dem aus Teil 1 sehr ähnlich:

image

Damit haben wir es eigentlich schon geschafft. Zum Schluss noch ein kleiner Hinweis. Natürlich ist dieser Weg um einiges einfacher, aber es gibt auch einen kleinen Haken, nämlich dass das Framework begrenzt ist. Das bedeutet, dass man nicht alles darüber schnell und ohne selber Code zu schreiben lösen kann, viele Anforderungen müssen immer noch von Hand oder mit Hilfe von anderen Frameworks implementiert werden.

Das erweiterte Demoprojekt aus Teil 1 gibts hier: Download [VS2010 c#]

<< Teil 1

kick it on dotnet-kicks.de

 

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

6Mrz/111

Twitter for iPhone: “Quick-” bzw. “Trends”-Bar entfernen

Falls ihr ein iPhone besitzt und die Twitter for iPhone App nutzt werdet ihr seit dem letzten Update etwas sehr sehr nerviges festgestellt haben, nämlich die neue halbdurchsichtige Leiste über der Timeline.

Diese so genannte Trends-Bar kann man leider nicht über die Einstellungen der App entfernen. Was noch dazu kommt, ist dass das was diese Leiste anzeigt (für mich) überhaupt keinen Sinn ergibt und einfach nur stört!

An dieser Stelle gibt eine gute Nachricht für alle die ihr iPhone gejailbraked haben, denn die können im Cydia Store die Erweiterung namens "Twizzler" installieren und müssen diese nutzlose Leiste nie wieder sehen!

Falls ihr euer iPhone nicht gejailbraked habt, bleibt euch nur die Wahl eine ältere Version der Twitter App zu installieren oder zu einem anderen Twitter Client zu wechseln!

7Feb/118

Wuala: Konkurrenz für Dropbox?

Ich denke die meisten von euch werden den Synchronisations Dienst Dropbox kennen, wenn nicht dann hier eine kurze Zusammenfassung:

Dropbox ist ein Webdienst, der ein Netzwerk-Dateisystem für die Synchronisation von Dateien zwischen verschiedenen Rechnern und Benutzern bereitstellt und damit gleichzeitig eine Online-Datensicherung ermöglicht. Zum Zugriff gibt es Programme für die BetriebssystemeMac OS XiOSLinuxAndroidBlackberry und Microsoft Windows.

Dropbox Logo

Ich nutze Dropbox nun schon seit mehreren Jahren und bin begeistert und würde es jedem sofort empfehlen. Wers testen mag kann sich hier mit 250 MB Extra Speicher anmelden klick (Ref Link von mir).

Seit einiger Zeit gibt es aber nun auch Konkurrenz namens Wuala.

Wuala Logo

Im Grunde verfolgt Wuala eine ähnliche Idee wie Dropbox, nämlich einen Speicher anzubieten, der von überall auf der Welt erreichbar ist und zwischen mehreren Computern Synchron ist.

Was Wuala aber besonders macht, ist die Art der Aufbewahrung eurer Daten, denn Wuala verschlüsselt eure Daten BEVOR diese ins Internet übertragen werden. Das bedeutet, dass niemand außer euch Zugriff auf eure Daten erlangen kann, nicht mal Wuala selbst. Das macht diesen Speicher besonders sicher!

Übrigens wird euer Passwort niemals übertragen bei Wuala, das bedeutet, wenn euer Passwort weg ist, kommt ihr nie wieder an eure Daten, also aufpassen.

Falls ich euch nun doch neugierig gemacht habe könnt ihr euch hier über meinen Ref Link mit einem GB extra anmelden.

Wenn ihr dann erst einmal angemeldet seit könnt ihr unter Optionen->Speicher kaufen->Code einlösen noch folgende Codes einlösen und euren Speicher erweitern:

  • I-KNOW-DOMINIK : 1 GB
  • I-KNOW-CAROLA : 1 GB
  • I-KNOW-FABIUS : 1 GB
  • I-KNOW-LUZIUS : 1 GB
  • I-KNOW-THOMAS : 1 GB
  • I-KNOW-JONAS : 1 GB
  • I-KNOW-MARCEL : 1 GB
  • I-KNOW-MARIUS : 1 GB
  • I-KNOW-DARIO : 1 GB
  • CONNECT-WITH-SUPPORT : 1 GB
  • SKYFISH-IS-COOL : 1 GB

Jeder dieser Codes bringt euch dann nochmal 1GB extra. Es bleibt abzuwarten, wie sich dieser Dienst entwickelt (Dropbox hat auch klein angefangen) und vielleicht wird die Bedienung auch noch überarbeitet und vereinfacht, dann bin ich auch definitiv aktiv dabei, aber so wie es nun ist ist es mir einfach zu umständlich, und so paranoid bin ich noch nicht ;-)

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

22Nov/104

Handy-abzocke – Diesmal hat es mich erwischt

Bild von www.it-news-world.de

Oh nein, habe ich mir gedacht, als ich meine letzte Rechnung gesehen habe. Eine Rechnung eines Drittanbieters namens Carmunity.com GmbH tauchte auf meiner Rechnung auf und will 15 € von mir für irgendwelche Dienstleistungen haben, von denen ich noch nie etwas gehört habe, noch ist mir der Namen dieser Firma irgendwie über den Weg gelaufen.

Dabei bin ich nicht einer dieser Leute die überall ihre Nummer eintragen und erkenne solche "Nummer-Sammel-Seiten" auf den ersten Blick.

Meine erste Anlaufstelle war nun die Hotline der Telekom. Schon mit schlechter Laune im Gepäck ging da der tolle Computer dran und begrüßte mich herzlich, und da wusste ich, der Tag kann noch schlechter werden... Nach dem ich "Rechnung" in das Telefon gerufen habe sagte man mir, dieser Dienst sei unter der gewählten Nummer nicht erreichbar und ich solle eine andere Hotline anrufen.

Gesagt - getan, wieder begrüßte mich eine Computer-stimme und frage mich was ich da will. Ich weiß ja nicht wie es euch da geht aber ich muss dann immer sofort an diese Werbung denken:

Nach dem ich endlich einen menschlichen Mitarbeiter am Telefon hatte habe ich ihr das Problem geschildert und sie bestätigte mir, dass diese Firma bei weitem kein unbekannter mehr ist, sagte mir aber auch, dass sie da nichts machen können und ich den Rechnungsbetrag zurück buchen soll und dann nur den Differenzbetrag überweisen soll, also ohne diese Abo-Gebühr.

Das hätte natürlich zur Folge, dass die Telekom dann Stress machen und Mahnungen zu mir schicken, da ich ja nicht den Ganzen Betrag überweise, die könnten sogar meinen ganzen Anschluss sperren... tolle Aussichten.

Nebenbei hat sie mir auch erzählt dass man Drittanbieter Dienste komplett abstellen kann, was aber nur für zukünftige Anfragen gilt - ich würde es jedem empfehlen!

Zum Schluss erwähnte sie noch, dass ich mir dieses Abo eingefangen habe weil ich ein iPhone Besitze, es scheint wohl Vorfälle zu geben, bei denen Apps hinter dem Rücken des Benutzers die Mobilfunknummer ermitteln und dann Abos abschließen. Und solche APIs gibts es auf dem iPhone tatsächlich - danke Apple für dieses Feature. Aber die Android Plattform ist da auch vorne mit dabei.

Als ich dann ein wenig gegoogelt habe fiel mir auch auf, dass ich nicht allein bin. Viele sind wohl in diese Kastenfalle getappt.

Ich habe dann eine E-Mail an das "Unternehmen" geschickt und zu meiner Überraschung kam recht schnell die Antwort, dass meine gebuchte Videoflatrate gekündigt wurde...

Achja, die Videoflatrate... naja wenigstens ging die Kündigung schnell und einfach. Ich habe dem Vertrag nicht widerrufen, da ich keine lust hatte mich mit der Telekom rumzuschlagen wegen der zurückgebuchten Rechnungen da ist mir das zu viel Aufwand für 15 Euro.

Wegen sowas rate ich euch wirklich mal bei der Hotline anzurufen und Drittanbieter "Leistungen" zu deaktivieren - nur Stress mit dem Scheiß!

Ist euch so etwas auch schon mal passiert?

11Nov/101

ASP.NET MVC3: Was gibts neues?

Einige von euch haben es sicher mitbekommen, dass vor Kurzem der Release Candidate (RC) von ASP.NET MVC3 veröffentlich wurde. Download, Changelog. Diese neue Version bringt einige für uns Entwickler tolle neue Funktionen und Vereinfachungen mit.

Die wohl auffälligste Neuerung ist die neue ViewEngine namens Razor, diese sorgt dafür, dass die Views um einiges schlanker und lesbarer werden durch die Einführung einer neuen Syntax.

Ich will mit euch ein kleines Beispielprojekt erstellen in dem wir Schritt für Schritt einige der Neuerungen durchgehen.

Fangen wir an und erstellen ein neues MVC3 Projekt in Visual Studio und bereits hier gibts es was Neues zu betrachten:

Bild 1: Der Neue Projekt erstellen Dialog

Da wir von Vorn beginnen möchten erstellen wir ein neues Leeres Projekt und wählen die neue Razor ViewEngine.

Layout

Wenn man nun einen Blick auf den Projektmappenexplorer wirft, wird man drin nicht viel finden, lediglich eine CSS- und zwei cshtml-Dateien. Die cshtml-Dateien fangen auch noch mit einem Unterstrich (_) an und haben irgendwas mit Layout im Namen.

Was ist das?

Öffnen wir zunächst im Shared-Ordner die Datei _Layout.cshtml.

image

Diese Datei kann man mit einer MasterPage aus MVC2 vergleichen. Wenn ihr genau hinschaut werdet ihr im Title-Tag einen Platzhalter finden und auch im body-div ist einer namens „@RenderBody()“.

Die Layoutseiten in MVC3 funktionieren anders als die in MVC2, auch wenn diese Seite auch Platzhalter besitzt die später mit Inhalt befüllt werden fällt dennoch die Methode RenderBody() auf. Diese Methode ist in jeder Layout-Seite drin und steht immer an der Stelle wo später der Inhalt der Seite  stehen wird. Neben der RenderBody()-Methode gibt es auch die RenderSection()-methode, die auch einen Namen bekommen und auch als optional markiert werden können.

Was auch neu ist, ist dass wir keine <% %> Tags mehr haben in die wir den ASP.NET Code schrieben können, das alles übernimmt nun das @-Zeichen. Das System ist dabei so intelligent, dass es erkennt bis wohin der Code geht weswegen man auch kein schließen Tag benötigt. Weitere Informationen zu der Razor Syntax.

Wie man sieht sind die ganzen JavaScript Verweise auskommentiert. Bitte entfernt die Kommentarmarkierung, da wir diese Skripte bald benötigen.

Gut, schleißen wir diese Datei und werfen nun einen Blick in die „_ViewStat.cshtml“ in unserem Views-Ordner:

image

Der Inhalt hier ist wie man sieht sehr übersichtlich Smiley

Was macht diese Datei nun? Wie man sieht verweist diese auf die _Layout.cshtml die wir eben betrachtet haben, dabei sorgt dieser Verweis dafür, dass alle Views in dem Views-Ordner inkl Unterordner diesen Verweis auch erhalten. Das hat zur Folge, dass man nun nicht mehr in jeder einzelnen View diese Referenz auf die Layoutdatei eintragen muss und spart sich so den redundanten Code.

Viel mehr gibt es dazu eigentlich auch nicht zu sagen. Gehen wir nun zum nächsten Schritt und erstellen eine neue View.

Views

Wenn ihr den View-Hinzufügen Dialog wählt werdet ihr auch hier eine Veränderung feststellen:

image

Wie man sieht kann man nun auch bei jeder einzelnen View wählen, welche ViewEngine man hier gern verwenden möchte. Legen wir eine gewöhnliche View an.

image

Die neue View enthält nun nur diese paar Zeilen Code (siehe Bild oben).

Zuerst wird ein Codeblock aufgemacht mit der @{ … } Syntax, das bedeutet, dass nun nur noch ASP.NET Code kommt bis die schließen Klammer kommt, auch über mehrere Zeilen.

Innerhalb dieses Codeblocks füllen wir nun den Titel unserer Seite, wenn ihr euch erinnern könnt wurde diese Variable in der MasterPage im Title-Tag wieder ausgegeben.

image

Man beachte hier, dass diese Property dynamisch erstellt wird und es die Property „Title“ eigentlich gar nicht gibt. Diese wird dann zur Laufzeit generiert und mit Inhalt befüllt. So kann man beliebig viele solcher Properties anlegen.

In Zeile 3 geben wir an welche MasterPage hier verwendet werden soll, da wir aber bereits die Datei „_ViewStat.cshtml“ in unserem Views-Ordner liegen haben müssen wir innerhalb der View keinen Verweis mehr auf eine Masterpage setzen. (Außer wir wollen eine andere Nutzen) Also können wir diese Zeile aus unserem Code löschen.

Nun fängt schon ab Zeile 6 der normale HTML Quelltext an, ohne dass wir irgendwo einen Zugehörigkeitsbereich definiert haben. Das ist ein weiteres MVC3 / Razor Feature, denn alles wird an der stelle in der MasterPage eingesetzt wo wir die Methode RenderBody() aufrufen. Eine Ausnahme besteht, wenn wir Sektionen in der Masterpage definiert haben, diese würden dann dementsprechend der passenden Sektion zugeordnet werden.

So könnte eine Sektion aussehen:

image

Das wars nun soweit zu dieser View. Wenn ihr mögt könnt ihr nun weiter damit arbeiten wie mit einer gewöhnlichen View.

Nun wollen wir mal ein Formular anlegen, dass wir zum Registrieren eines Benutzers nutzen wollen. Dazu benötigen wir zunächst ein Model auf das wir dann unsere View mit der Form  typisieren.

Legen wir also eine neue Klasse im Models-Verzeichnis an. Die Model Klassen verhalten sich in MVC3 eigentlich genauso wie in MVC2, nun sind aber einige neue Attribute hinzugekommen die ich euch hier mal vorstellen möchte:

image

Wie ihr seht hat meine Modelklasse 5 Eigenschaften. Die ersten drei sind mit dem Attribut [Required] markiert und sind somit Pflichtfelder. Alle Eigenschaften besitzen ein [DisplayName()] Attribut, dass den Text enthält, der später in der View angezeigt werden soll.

Kommen wir nun zu den neuen Attributen. Erstmal das [Required, Compare(…)] Attribut. Dieses Attribut sorgt hier dafür, dass „RepeatEmail“ mit „Email“ verglichen wird und übereinstimmen muss damit die Validierung erfolgreich ist. So müssen wir diese zwei Werte nun nicht mehr im Controller manuell vergleichen.

Weiter unten bei der About-Eigenschaft finden wir ein weiteres neues Attribut namens [SkipRequestValidation] – Im Prinzip sagt der Name schon alles aus. Dieses Attribut sorgt dafür, dass diese Property beim Binding keine Exception wirft wenn dort HTML enthalten ist.

Früher musste man dann im Controller die Action mit einem [ValidateInput(false)] markieren, was natürlich immer noch funktioniert, aber nun kann man auch einzelne Properties bequem markieren ohne gleich für die ganze Methode den Validationinput abzuschalten.

Hier gibts es nun sogar die Möglichkeit bestimmte Properties von der Validierung auszuschließen:

image

Hier werden die Properties “Body” und “Summary” nicht auf HTML Inhalt überprüft.

Wie ihr sehen könnt habe ich ein Attribut auskommentiert. Auf dieses Attribut habe ich mich persönlich sehr gefreut, aber es scheint nicht zu funktionieren (oder ich mache etwas falsch, wenn ihr meinen Fehler seht bitte kommentieren ACHTUNG: dazu habe ich hier ein Update geschrieben)

Dieses RemoteAttribut erlaubt es eine Eigenschaft an eine Methode in einem Controller zu binden und währen der Ausführung der View beim Client im Hintergrund über Ajax aufzurufen. Für den Fall von der Property Name würde die Methode UserNameAvailabla im Controller Register aufgerufen werden, welche ein boolean zurück gibt. So wird dann dynamisch eine Fehlermeldung auf der View erscheinen.

Wenn man dieses RemoteAttribut nun benutzen möchte muss man natürlich die oben angegebene Methode im angegebenen Controller implementieren, zB so:

image

Diese Methode wird dann beim Validieren per Ajax aufgerufen und zeigt dann dementsprechend auch eine Fehlermeldung an (Falls nötig):

image

Zum Schluss möchte ich noch darauf hinweisen, dass ich ein bestimmtes kleines Feature vermisst habe, nämlich eine bequeme Möglichkeit einen String auszugeben ohne diesen mit HTML zu Encoden. Denn soweit bietet Razor leider keine Möglichkeit dafür. Deswegen muss man hier mit einer eigenen kleinen Extension Methode aushelfen.

Das wäre es dann nun auch für heute. Ich habe ein kleines Beispiel Projekt vorbereitet, dass ihr hier herunterladen könnt. (.NET 4.0 VS2010)

24Okt/105

Ein Steiniger Weg: SuperDrive gegen SSD eintauschen

Diejenigen von euch die mir bei Twitter folgen haben es wohl schon mitbekommen, dass ich das DVD Laufwerk meines MacBooks (late 2008) genannt SuperDrive gegen eine SSD eintauschen wollte.

Warum der Stress?

Also ich weiß nicht wie es bei euch ist, aber ich nutze das im MacBook verbaute DVD Laufwerk so gut wie nie! Ich habe damit mal Windows installiert, oder auch mal Mac OS, ein mal habe ich sogar mal ein paar Dateien auf eine DVD gebrannt, aber mehr war es auch wirklich nicht.

So gut wie alle Daten die auf meinen Rechner kommen tuen es entweder übers Internet oder über einen USB-Stick. Mal ernsthaft wie oft verwendet ihr eure DVD Laufwerke?

Da ich schon seit längerem mit dem Gedanken Spiele mir eine SSD anzuschaffen, aber immer gezögert habe, da diese recht teuer sind und wenig Speicherplatz bieten als das man sie gegen die verbaute Festplatte tauschen könnte, habe ich mir gedacht, hey, warum nicht den Teil ausbauen, den du sowieso nicht nutzt?

Erste Schwierigkeiten

Wie ihr euch sicher denken könnt kann man ein ganzes DVD Laufwerk nicht einfach gegen eine viel kleinere SSD tauschen. Erstens ist da die Größe die nicht passt und zweitens auch der Anschluss, der ein etwas kleinerer ist am Laufwerk.

Ein Adapter muss her.

Meine ersten Suchversuche führten mich zum Optibay von MCE. Das hat mich wirklich aus den Socken genauen! Da soll man wirklich für ein Stück Allu mit einem, SATA Adapter drauf $100 plus Versand und Zoll bezahlen. – Nein danke!

Kurz darauf habe ich bei eBay ein “Konkurrenz”-Produkt gefunden, dass nicht nur Optisch besser aussah, sondern mir auch noch preislich besser gefiel (13€ inkl Versand).

Knapp drei Wochen später kam das Päckchen dann auch bei mir an:

jww

Die SSD

Man kann wirklich viel Zeit in die Suche nach der “richtigen” SSD investieren, so war ich @Twittlor (Marek) wirklich dankbar für seinen Tipp, der mich zur OCZ OCZSSD2-2VTXE60G 60GB führte.

OCZ-Vertex-2-MLC-2_5-inch-SSD

Nach einer kleinen Google Recherche (hier ein Testbericht) ging noch am selben Tag die Bestellung bei Amazon ein.

Der Ein/Umbau

Zwei Tage später hielt ich die SSD in den Händen. Nun hieß es ran an den Speck.

Mein Plan war folgender:

  1. Alte Festplatte formatieren und Mac OSX über DVD neu installieren (50GB)
  2. DVD Laufwerk ausbauen, SSD einbauen und Windows über einen USB-Stick installieren

Wie ich finde ein sehr guter und einfacher Plan, doch leider habe ich meine Rechnung ohne Apple gemacht.

Das Apple-Problem

Ich weiß nicht warum Apple immer mit dem Slogan wirbt, dass ihre Systeme so einfach wären. Denn sie sind es nicht!

So musste ich überrascht feststellen, dass das MacBook nicht von meinem Windows Installations USB-Stick booten konnte, obwohl andere Notebooks kein Problem war.

Nach einer Kurzen Suche fand ich heraus, dass Macs NUR Mac OS von einem Stick installieren können! Windows kann man NUR von CD/DVD installieren – was ist denn das für ein Kindergarten?

Der Ein/Umbau – der zweite Versuch

Nun musste ich meinen oberen Plan natürlich verwerfen, da ich Windows nicht mehr hätte installieren können, wenn das DVD Laufwerk erst einmal draußen war.

Also neuer Plan:

  1. Alte Festplatte formatieren und Mac OSX über DVD neu installieren (50GB)
  2. Alte Festplatte ausbauen, SSD einbauen und Windows über DVD neuinstallieren
  3. SSD ausbauen und Alte Festplatte wieder einbauen
  4. DVD Laufwerk ausbauen und SSD einbauen

ARGH! – Nun gut, geht nicht anders.

Als ich anfing nach den Anleitugen von iFixit.com die Festplatte auszubauen kam schon das nächste Problem. Die eine Schraube, die die Festplatte befestigt war so enorm festgeschraubt, dass ich den Schraubenkopf und einen Schraubenzieher zerstörte bei dem Versuch diese zu lösen.

Toll – fängt ja gut an. Nun war die Schraube nicht mehr lösbar, also musste schweres Geschütz her und die Schraube musste aufgebohrt werden.

Ich weiß nicht, ob ihr schon mal in euren Notebook rumgebohrt habt aber es war wirklich kein schönes Gefühl. Aber gut nach weiteren 20 Minuten war die Schraube raus.

Foto 2

Nun konnte ich die SSD problemlos einbauen und Windows von der DVD installieren.

Nun kam der lustige Teil, der Ausbau des DVD Laufwerks. Wenn ihr schon mal in das Innere eures MacBooks geschaut habt wisst ihr, dass es keine einfache Angelegenheit ist, da diverse andere Teile das Laufwerk verdecken und somit vorher ausgebaut werden müssen um überhaupt an das Laufwerk ranzukommen.

Übrigens, wenn es bei euch noch nicht der Fall ist, verliert ihr bei diesem Schritt eure Garantie und Gewährleistungsansprüche gegenüber Apple.

Wer hierzu mehr wissen will schaut einfach in die Anleitung von iFixit.

Foto 1 (1)

Nach einigem Rumgefrickel war das Laufwerk raus. Phuh

Nun musste die SSD in den Chinesischen Adapter, und genau hier hat man die Qualitätsdefizite zu spüren bekommen die man durch den niedrigen Preis inklusive bekommen hat.

Denn die Stecker passten nicht 100%ig zusammen, da in dem Adapter der mittlere Separator ein wenig zu dick war. Also musste hier das Cutter Messe raus um diesen Missstand manuell zu beheben. Aber nach ein paar Minuten als Chirurg passte die SSD auf den Adapter.

Foto 5Tief durchatmen und den Adapter nun an die große leere Stelle im MacBook einbauen:

Foto 3

Und so sah dann das Ergebnis aus:

Foto 2 (1)

Der Adapter ist minimal dicker als das DVD Laufwerk, weswegen etwas schwieriger war nun die ganzen Teile wieder zusammenzusetzen.

Da die Technik im MacBook extrem klein ist sehen dem entsprechend auch die Anschlüsse aus, und sind EXTREM winzig! Manchmal hatte ich schon Angst diese überhaupt zu berühren. Die Kontakte sind sehr klein und sehr nah bei einander und so gut wie jeder Geräteanschluss ist über einen Adapter an dem Motherboard angeschlossen.

Inbetriebnahme

Tatsächlich ist das MacBook nach der Operation auch wieder angegangen und hat beide Festplatten problemlos erkannt. Bisher funktioniert auch alles wie gewohnt.

Zu Performance will ich noch keine Angaben geben, da ich nun erst einmal dabei bin alles neu zu installieren. Was ich aber bisher sagen kann, ist, dass mir dieses kleine Geräusch fehlt, dass das DVD Laufwerk immer gemacht hat wenn es anging, dieses kleine “Zucken” wenn man so will.

Das ganze Gerät ist des weiteren komplett lautlos, wenn nicht grade ein Flash Video läuft. Zwinkerndes Smiley

Konfiguration

Bei einer SSD gibt es auch einige Einstellungen, die man am Betriebssystem vornehmen muss sollte, um die Lebenserwartung zu erhöhen. Ein wenig Arbeit nimmt uns Windows 7 (und nur 7) ab und stellt schon mal die Defragmentierung ab und macht ein paar weitere Konfigurationen.

Die weiteren Schritte habe ich aus dieser sehr guten Anleitung wo alle weiteren wichtigen Schritte, wie das deaktivieren des Prefetching und Superfetching beschrieben wird.

Testbericht

Wenn ich ein wenig Zeit mit dem Gerät verbracht habe, werde ich hier auch noch einen gesonderten Erfahrungsbericht schreiben.

Wenn ihr Fragen haben solltet einfach hier als Kommentar posten.

veröffentlicht unter: Allgemein, Computer, Internet 5 Kommentare
Get Adobe Flash player