Neues in ASP.NET 5, Teil 3: Änderungen in Visual Studio 2015

Seite 2: Open Source inside

Inhaltsverzeichnis

Eine mit den ASP.NET-5-Vorlagen angelegte Website und ein Web-API-Dienst im Projektmappen-Explorer von Visual Studio 2015 (Abb. 4)

Die nächste Verwunderung gibt es für altgediente ASP.NET-Entwickler nach dem Anlegen eines Projekts mit den ASP.NET-5-Vorlagen "Web API" und "Web Site". Im Projektmappen-Explorer sieht man jetzt einige ganz neue Einträge (s. Abb. 4).

Unter "Solution" gibt es nun einen neuen Ordner /src (für Source) und erst darunter die Projekte. Auf der Festplatte gibt es zusätzlich den im Projektmappen-Explorer nicht sichtbaren weiteren Ordner /artifacts für temporäre Produkte während des Übersetzungsvorgangs. Endprodukte dürfen hier jedoch nicht liegen. Über diese Verzeichnisstruktur gab es in den letzten Monaten umfangreiche Diskussionen auf GitHub.

Der Ast "Referenzen" teilt sich in die beiden angesprochenen DNX-Varianten (wobei im Visual Studio 2015 Release Candidate die Bezeichnung DNX 4.5.1 falsch ist. Dort müsste DNX 4.6 stehen).

Der neue Projektmappenordner wwwroot, den es unter /src/wwwroot auch auf der Festplatte gibt, enthält alle statischen Dateien des Projekts (HTML, CSS, JavaScript, Grafiken, favicon.ico usw.). Er repräsentiert später die Zielstruktur.

Ebenfalls neu ist der Ast "Dependencies", den es so im Dateisystem allerdings gar nicht gibt. Die beiden Zweige "Dependencies/Bower" und "Dependencies/NPM" listen die verwendeten Pakete von Twitter Bower und Node Package Manager. Die Paketlisten ergeben sich aus den Dateien bower.json (für Bower) und package.json (für NPM) beziehungsweise dem Inhalt der Dateisystemordner bower_components und node_modules. Für die Verwaltung der Abhängigkeiten zu Bower und NPM gibt es in Visual Studio noch keine grafische Benutzeroberfläche wie bei Microsofts eigenem Paketmanager NuGet; die JSON-Dateien bieten eine hilfreiche Eingabeunterstützung für die Paketnamen und Versionsnummern (s. Abb. 5).

Visual Studio 2015 bietet Eingabeunterstützung für sowohl Paketnamen als auch Versionsnummern, und zwar für alle drei Paketmanager NuGet, Bower und NPM (Abb. 5)

Zu den im Standard geladenen Bower-Paketen gehören jQuery, jQuery Validation, hammer.js für Touch-Gesten, Twitter Bootstrap und Twitter Touch Carousel. Letzteres ist allerdings ein Paket, das seit über einem Jahr auf Version 0.8 steht und das auf der GitHub-Seite informiert: "This package is no longer maintained! We're searching for contributors". Es ist kurios, dass Microsoft in seinen Webprojektvorlagen auf so ein verwaistes Paket setzt. Die Beispiel-Webanwendung im Responsive Web Design, die die Projektvorlage aus diesen Bausteinen zusammensetzt, sieht man in Abbildung 6.

Die Projektvorlage für ASP.NET-5-Websites in Aktion (Abb. 6)

Bei den NPM-Paketen findet man den Node.js-basierten Task Runner Gulp und das von Gulp verwendete Paket rimraf, das Verzeichnisse rekursiv löschen kann. Dazu passend enthält die Datei gulpfile.js die Aufgabendefinitionen für Gulp. Im Standard findet man in der Datei die Aufgabe "copy", die Dateien aus dem Verzeichnis bower_components nach wwwroot/lib kopiert, sowie die Aufgabe "clean", die den kompletten Inhalt des Ordners wwwroot/lib löscht. Über das neue Visual-Studio-Fenster "Task Runner Exlorer" (s. Abb. 7) können Entwickler die Aufgaben zu den vier Ereignissen "Before Build", "After Build", "Clean" und "Solution Open" zuweisen. Die Zuweisung speichert Visual Studio in einem Kommentar zu Beginn der Datei gulpfile.js.

In Gulp und Grunt definierte Aufgaben kann man im Task Runner Explorer vier Ereignissen in Visual Studio per "Binding" zuweisen (Abb. 7).

Neben Gulp unterstützt der Task Runner Exlorer den Gulp-Konkurrenten Grunt. Ihn muss man als NPM-Paket nachinstallieren (s. Abb. 6) und dann dem Projekt eine Datei gruntfile.js hinzufügen. Sodann erscheinen die dort definierten Aufgaben auch im Task Runner Explorer (s. Abb. 7). Ein grundsätzlicher Unterschied zwischen Gulp und Grunt ist, dass die Konfiguration bei Gulp in JavaScript-Syntax erfolgt:

/// <binding AfterBuild='copy' Clean='clean' />
var gulp = require("gulp"),
rimraf = require("rimraf"),
fs = require("fs");

eval("var project = " + fs.readFileSync("./project.json"));

var paths = {
bower: "./bower_components/",
lib: "./" + project.webroot + "/lib/"
};

gulp.task("clean", function (cb) {
rimraf(paths.lib, cb);
});

gulp.task("copy", ["clean"], function () {
var bower = {
"bootstrap": "bootstrap/dist/**/*.{js,map,css,ttf,svg,woff,eot}",
"bootstrap-touch-carousel":
"bootstrap-touch-carousel/dist/**/*.{js,css}",
"hammer.js": "hammer.js/hammer*.{js,map}",
"jquery": "jquery/jquery*.{js,map}",
"jquery-validation": "jquery-validation/jquery.validate.js",
"jquery-validation-unobtrusive":
"jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"
}

for (var destinationDir in bower) {
gulp.src(paths.bower + bower[destinationDir])
.pipe(gulp.dest(paths.lib + destinationDir));
}
});

Grunt verwendet hier hingegen im Wesentlichen JSON verwendet.

/// <binding AfterBuild='less' />
// This file in the main entry point for defining grunt tasks and
// using grunt plugins. Click here to learn more.
// http://go.microsoft.com/fwlink/?LinkID=513275&clcid=0x409

module.exports = function (grunt) {
grunt.initConfig({

// fuer LESS:
less: {
development: {
options: {
paths: ["Assets"],
},
files: { "wwwroot/css/site2.css": "assets/site2.less" }
},
},
bower: {
install: {
options: {
targetDir: "wwwroot/lib",
layout: "byComponent",
cleanTargetDir: false
}
}
}
});

// This command registers the default task which will
// install bower packages into wwwroot/lib
grunt.registerTask("default", ["bower:install"]);
grunt.registerTask("default", ["less:development"]);
// The following line loads the grunt plugins.
// This line needs to be at the end of this this file.
grunt.loadNpmTasks("grunt-bower-task");

// Zusatz fuer LESS-Task:
grunt.loadNpmTasks("grunt-contrib-less");
};

Gulp ist damit oft flexibler.