Unterlagen zu meinem ‘ASP.NET MVC 3 von 0 an’ Vortrag
Gestern am 04.04.2011 habe ich für die .NET Online Usergroup einen Vortrag für ASP.NET MVC 3 Einsteiger gegeben, vielleicht wart ihr sogar dabei.
Da schnell die Frage nach den Folien und dem Beispielcode der während der Präsentation entstand aufkam, möchte ich diese hiermit nachliefern.
Installation
In meinem Vortrag ging ich nicht darauf ein, wie man ASP.NET MVC installiert, dies will ich hiermit nachliefern. Die Installation erfolgt schnell und einfach über den ASP.NET MVC Installer den ihr auf der ASP.NET MVC Homepage bekommt oder über diesen Direktlink. Die Installation an sich ist nicht weiter erwähnenswert ![]()
Nach der Installation werden ihr die Projektvorlage in Visual Studio vorfinden.
Kostenlos ASP.NET MVC Entwickeln
Falls ihr keine Visual Studio Lizenz besitzt könnt ihr den Visual Web Developer benutzen um MVC zu entwickeln:
http://www.microsoft.com/germany/express/products/web.aspx
Aufzeichnung
ASP.NET MVC von 0 an from .NET Online User Group on Vimeo.
Präsentation
Code (mit Kommentaren)
Feedback & Fragen
Falls du bei dem Vortrag dabei warst und noch Fragen hast oder einen (Verbesserungs)vorschlag oder Feedback hast kannst du das auch gerne als Kommentar posten.
Bis zum nächsten Mal!
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:
Dies habe ich auch als Vorlage genommen und meine Methode im Controller implementiert:
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:
Dieser Request kommt erfolgreich auf dem Server an und wird korrekt verarbeitet. Als Response kommt dann folgendes zurück:
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:
Der bessere Weg wäre wohl ein JSON Result:
Nun funktioniert auch alles wie es soll und ich kann ruhig schlafen ![]()
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.
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:
Der Inhalt hier ist wie man sieht sehr übersichtlich ![]()
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:
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.
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.
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:
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:
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:
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:
Diese Methode wird dann beim Validieren per Ajax aufgerufen und zeigt dann dementsprechend auch eine Fehlermeldung an (Falls nötig):
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)
ASP.NET MVC 2: Custom ErrorPages anlegen
Wenn man Webseiten entwickelt möchte man diese natürlich möglichst anschaulich für den Nutzer gestalten, und dazu gehört es auch für den Benutzer anschauliche und auch verständliche Seiten zu präsentieren, auch wenn mal ein Fehler auftaucht. Im Normalfall passen die Default-Fehlerseiten von ASP.NET leider nicht ins Bild der restlichen Seite, weswegen wir gezwungen sind unsere eigenen Fehlerseiten anzulegen.
Bild 1: Typische 404 Fehlermeldung von ASP.NET
Eigene Fehlerseiten sind unter ASP.NET MVC 2 schnell in vier Schritten eingerichtet.
1. Änderungen an der Web.config vornehmen
Zunächst müssen in der Web.config die customErrors eingeschaltet werden. Hier können die Attribute "defaultRedirect", welches die Adresse definiert die im Falle eines Fehlers aufgerufen wird und "mode", dass einstellt ob Fehler angezeigt werden sollen oder nicht.
Mit den inneren "error"-Ästen kann man dazu noch spezifische Seiten zu einzelnen Fehlercodes zuweisen. Man kann hier sowohl eine absolute Adresse angeben oder nur eine relative. Für alle nicht spezifizierten Errorcodes wird die Url aus dem customError Tag benutzt.
Wenn ihr diese Einstellungen Lokal testen wollt dann solltet ihr auch den "mode" auf "On" stellen, da ihr euere Seiten sonst nicht zu Gesicht bekommt.
2. Anlegen des Controllers für die Fehlerbehandlung
Wie ihr sehen könnt habe ich hier eine lokale Adresse angegeben. Hierbei wird der Controller "Error" aufgerufen und je nach Fehlercode eine andere Methode.
Im Controller haben wir hier eigentlich nichts besonderes:
Ich war an dieser Stelle mal faul und habe nur eine einzige View für alle Fehler angelegt, die dann die übergebene message ausgibt. Dazu kommt noch, dass wir der Response noch den passenden HttpStatusCode übergeben, da manche Anwendungen danach gehen und so prüfen, ob ein Aufruf erfolgreich war.
3. Die View
Wie eben erwähnt macht die View in meinem Beispiel nichts anderes als den Inhalt der Messagevariable auszugeben. Hier könnt ihr natürlich eurer Kreativität freien Lauf lassen und auch für jeden Error eine einzelne View anfertigen.
4. Glogal.asax - Catch All Route registrieren
Zum Schluss sollten wir noch eine sogenannte Catchall Route einrichten, die wir nach allen unseren Routen positionieren damit diese nur greifen kann, wenn keine der anderen gepasst hat, diese Route wird in jedem Fall aufgerufen, wenn keine der vorderen gepasst hat.
Wenn die CatchAll Route greift wird der Home Controller aufgerufen und die Action "NotFound" ausgeführt.
Im Grunde sind wir nun fertig, alle von uns eingetragenen Fehler werden nun abgefangen und durch von uns präparierten Seiten ersetzt. Das einzige was noch passieren kann ist dass ihr im IIS andere ErrorPages eingestellt habt, dann dann werden diese angezeigt und nicht die von euch erstellten. Hier müsst ihr die "Error Responses" auf "Detailed errors" stellen.
HowTo: Bilder als Links benutzen in ASP.NET MVC
In diesem Artikel geht es um eine eigentlich ganz simple Angelegenheit, nämlich Bilder-Links in ASP.NET MVC. Um Links zu generieren wird hier eine HtmlHelper Klasse bereitgestellt, die die Links abhängig von der gewünschten Action und dem gewünschten Controller generiert, das ist eigentlich eine feine Sache, nur lassen sich damit leider keine Bilder-Links generieren.
Das Problem an der Sache ist, dass der HtmlHelper seine Ausgabe für HTML formatiert und somit einer Übergabe von "<img src="..." alt="..." />" als Linkname nicht verarbeitet werden würde, sondern direkt so ausgegeben.
Ich habe mich dann an Google gewendet und viele verschiedene Ansätze gefunden um das Problem zu lösen oder wenigstens zu umgehen. Hier gibt es allgemein gesagt zwei Lösungsansätze und man muss wohl selber entscheiden welches einem mehr Vorteile bietet und einem persönlich zusagt.
Ansatz 1: Den a-Tag und den img-Tag selber anlegen und die Route mit der UrlHelper-Klasse generieren. Hier ein paar Beispiele:
<a href="<%= Url.RouteUrl(">">
put in <span>whatever</span> you want, also <img src="a.gif" alt="images" />.
</a>
<a href="<%= Url.Action(">">
<img src="../../Content/Images/add_48.png" alt="" />
</a>
<%= Html.ActionLink("__IMAGE_PLACEHOLDER__", "Products")
.Replace("__IMAGE_PLACEHOLDER__", "<img src="\" alt="" />")%>
Alle diese Methoden funktionieren und erzeugen einen Link der ein Bild umschießt, doch in meinen Augen ist das eine nicht so schöne Methode, denn solche Links werden doch ziemlich oft generiert und da fände ich eine schöne Methode wie Html.ActionLinkWithImage schon angenehmer und lesbarer.
Ansatz 2: Eine Eigene Helper Methode erstellen die die Generierung für uns übernimmt:
Nach etwas mehr Suchen habe ich auch eine Extension Method in Stephen Walthers Blog gefunden. Diese sieht wie folgt aus (habe die Funktion noch um den Parameter Controller ergänzt):
public static string ImageLink(this HtmlHelper helper, string actionName,
string controllerName, string imageUrl, string alternateText, object routeValues,
object linkHtmlAttributes, object imageHtmlAttributes) {
var urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
var url = urlHelper.Action(actionName, controllerName, routeValues);
// Create link
var linkTagBuilder = new TagBuilder("a");
linkTagBuilder.MergeAttribute("href", url);
linkTagBuilder.MergeAttributes(new RouteValueDictionary(linkHtmlAttributes));
// Create image
var imageTagBuilder = new TagBuilder("img");
imageTagBuilder.MergeAttribute("src", urlHelper.Content(imageUrl));
imageTagBuilder.MergeAttribute("alt", urlHelper.Encode(alternateText));
imageTagBuilder.MergeAttributes(new RouteValueDictionary(imageHtmlAttributes));
// Add image to link
linkTagBuilder.InnerHtml = imageTagBuilder.ToString(TagRenderMode.SelfClosing);
return linkTagBuilder.ToString();
}
//Benutzung:
<%= Html.ImageLink("Action", "Controller", "Pfad_zum_Bild", "alternativText", new { id = e.Id }, null, new { border = "0" })%>
Diese Funktion erledigt genau das was ich brauchte, sie generiert den benötigten Link und auch den IMG-Tag aus meinen übergebenen Informationen und sieht der Html.ActionLink() Methode dabei auch noch so ähnlich dass man gar nicht darauf kommt, dass es eine nachträglich eingefügte Extension ist
Falls ihr noch nach einer Möglichkeit nutzt das ganze auch mit streng typisierten Links zu nutzen solltet ihr in Mirkos Blog vorbeischauen, er hat auch dafür eine Extension Method gebastelt.
Ich bin mit dieser Lösung ganz zufrieden, doch interessiert es mich trotzdem, wie ihr das in euren Projekten handhabt und eure Links erstellt. Vielleicht habt ihr ja eine bessere Methode auf Lager.


