Vanilla MVC4: Step 07 – Minifying eigener CSS und Scripts

Zur Optimierung in der Frontstack-Programmierung gehört das Minify der eigenen Stylesheets und Scripte. Ebenso könnte ein Preprocessing notwendig sein auf Grund der gewählten Techniken. Zum Beispiel beim Einsatz von LESS oder SASS auf der Style-Seite bzw. CoffeeScript, TypeScript oder Dart auf der Script-Seite.

Die Alternativen der Vorverarbeitung:

  1. Externes Tooling (Grunt,yeoman)
  2. In das VisualStudio integriertes Tooling (Web Essentials)
  3. Runtime-Processing durch das Optimization Framework

Da ich weiterhin die IDE nicht verlassen will, fällt das externe Tooling weg. Zur Vorverarbeitung und Optimierung zur Laufzeit siehe wieder das Tutorial (Abschnitt LESS, CoffeeScript, SCSS, Sass Bundling im unteren Teil – leider kein Anker).

Also die Web Essentials 2012. Zunächst zur Installation: Erst die ASP.NET and Web Tools 2012 installieren (Web Plattform Installer oder Offline-Installer – siehe Link), dann die Web Essentials 2012 – Erweiterung.

Um ein bissl etwas zum Stylen zu haben, habe ich das Layout um eine Navigation / ein Menu erweitert und dabei auf den Helper @Html.ActionLink zurückgegriffen → System.Web.Mvc.Html ist der nächste Namespace, der den Razor-Views in ~/Views/Web.config hinzugefügt werden muss.

Zum Ausprobieren legt einfach mal jeweils ein Stylesheet und ein JavaScript-File an und lasst die Web Essentials arbeiten. Falls diese nicht sofort anspringen (bei mir ist das etwas uneinheitlich), dann einfach rechte Maustaste und jeweiligen Menüpunkt auswählen.

Ansonsten habe ich mein Projekt mit einem einfachen Bootstrap-Layout ausgestattet (und noch eine Action hinzugefügt: About). Checkout wie immer bei GitHub: Tag Url

Vanilla MVC4: Step 06 – CSS und JavaScript

Vorab: zur Installation der Abhängigkeiten im Front-Stack (HTML,CSS,JavaScript) gehe ich normalerweise andere Wege (bower, grunt, yeoman, jam, …). Aber wir wollen hier bei und in(!) einer IDE bleiben, also geht es los mit der NuGet-Console:

Install-Package jQuery
Install-Package Twitter.Bootstrap

Und wir erhalten zwei neue Verzeichnisse mit den Stylesheets und Scripts: Content und Scripts. Natürlich ließen sich diese ganz normal über link bzw. script-Tags einbinden. Aber wir gehen ja weiterhin den MVC4-Weg: Bundling and Optimization.

Also fehlt ein weiteres NuGet-Paket:

Install-Package Microsoft.AspNet.Web.Optimization

Der Namespace System.Web.Optimization ist in der ~/Views/Web.Config zu registrieren. Und jetzt lässt sich das Bootstrap Stylesheet einbinden im _RootLayout.cshtml über eine Zeile

@Styles.Render("~/Content/bootstrap.css")

Aber das Paket heißt nicht umsonst Optimization. Wir registrieren ein sogenanntes Bundle in unserer Global.asax:

BundleTable.Bundles.Add(
    new StyleBundle("~/css/bootstrap")
        .Include(
            "~/Content/bootstrap.css",
            "~/Content/bootstrap-responsive.css"
        )
);

Auch hier den Namespace (s.o.) nicht vergessen. Die Include-Methode kann übrigens auch Wildcards auswerten und kennt einen {version}-Part, der die Versionsnummer einschließt.

Dieses Bundle lässt sich jetzt über den Bundle-Namen (bei mir ~/css/bootstrap – andere Entwickler bevorzugen einen Ordner-Prefix bundles) einbinden. Und noch mehr: in der Debug-Konfiguration werden die beiden Stylesheets einfach eingebunden, in der Release-Variante die min-Files aneinander gehangen und nur ein einzelnes Stylesheet eingebunden.

Mehr dazu unter dem Tutorial-Link: asp.net tutorials

Alle Änderungen lassen sich wieder bei GitHub auschecken oder einfach einsehen. Tag Url oder Compare mit Step 05

Vanilla MVC4: Step 05 – Layout

Nachdem in den ersten vier Schritten die absoluten Basics geklärt wurden, geht es jetzt an die eigentliche Site. Dazu zunächst zu unserer Vorlage (die MS in Razor-Projekten jetzt Layout nennt – und nicht mehr MasterPage).

Neue View: ~Views/Shared/_RootLayout.cshtml

Neuer Controller: ~Controllers/DefaultController.cs

Und das Routing anpassen (DefaultController wechseln in der Global.asax).

Neue View: ~Views/Default/Index.cshtml

Das verknüpfte Layout kann direkt im View angegeben werden – oder in einer speziellen View: ~/Views/_ViewStart.cshtml. Ich hab mich für letzteres entschieden.

Für den Rest des Projektes bleibe ich bei Razor-Views, da diese auch für mich relativ neu sind bzw. ich bisher noch nicht produktiv damit gearbeitet habe.

Die neuen Dateien sind eingecheckt, Tag v0.0.5: GitHub

Vanilla MVC4: Step 04 – Razor View

Für den nächsten Schritt eine weitere MVC Action in unseren Controller einfügen: RazorIndex. Der Methoden-Rumpf ist komplett identisch zu der AspxIndex-Action.

Dann unter den Views einen neuen View Views\HelloWorld\RazorIndex.cshtml:

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>RazorIndex</title>
</head>
<body>
    <div>
        <h2>
            Hello World , this is a MVC Razor View.    
        </h2>    
    </div>
</body>
</html>

Zunächst ohne den ViewBag-Zugriff, um die Fehlermeldung wieder zu sehen:

MVC: No WebViewPage

Diesmal ist der Fix etwas weniger intuitiv: per Web.config muss dem Host eine Factory deklariert werden. Folgende Web.config bitte im Ordner Views anlegen: Link zu GitHub

Dann läuft das Beispiel erstmal. Nun kann auch World ersetzt werden durch @ViewBag.Name. Der Editor zeigte bei mir erst nach einem VisualStudio-Neustart keinen Fehler mehr an. Die Seite war aber lauffähig.

Vanilla MVC4: Step 03 – WebForm View

Für den nächsten Schritt fügen wir zunächst im HelloWorldController eine Action hinzu (Code-Snippet: mvcaction4):

public ActionResult AspxIndex(string name)
{
    ViewBag.Name = ">" + (name ?? "World") + "<";
    return View();
}

Return-Type ist diesmal eine ViewResult. Um zu demonstrieren, dass die WebFormViewEngine automatisch escaped, kapsele ich den übergebenen Namen in Tag-Klammern.

Bevor wir den View selbst hinzufügen, lohnt ein Blick auf die aktuelle Fehlerausgabe:

Serverfehler: View not found

Also: Ordner Views\HelloWorld anlegen und dort hinein eine neue View AspxIndex.aspx:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<!DOCTYPE html>
<html lang="de">
<head runat="server">
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>AspxIndex</title>
</head>
<body>
    <div>
        <h2>
            Hello <%: ViewBag.Name %>, 
            this is a MVC WebForm View.
        </h2>
    </div>
</body>
</html>

Wer das mit der rechten Maustaste auf dem View-Folder gemacht hat (untypisierte ASPX View), sollte die Base-Klasse in der Page-Direktive noch korrigieren.

Aufruf über http://localhost:1487/HelloWorld/AspxIndex/Michael (eventuell Port anpassen)