Understanding Visual Studio 2015 ASP.NET Web Project Changes
Overview
Microsoft has recently released Visual Studio 2015 Preview for evaluation. Along with Visual Studio Microsoft has announced that it will open source complete ASP.NET stack and make it hostable on Linux as well as Mac. Microsoft has changed their web project significantly to make it work across open source platforms. Visual Studio 2015 preview brings a lot of enhancements in the editor as well as one of the significant components that ship with it is ASP.NET v5 and total change in project structure of web applications. In an effort to embrace open source they have made a lot of changes to to the project templates to utilize a whole bag of popular open source technologies like NPM, Grunt and Bower. Enabling the use of popular open source package managers saves Microsoft from duplicating and maintaining the rapid speed of changes and new developments that are happening on the web. For example instead of building their open Less to CSS compiler and keeping it updated, now they enable developers to use popular open source versions of the same.
This blog post tries to get a better understanding of the new components of the ASP.NET 5 web application project as well as get an understanding of the changes that have been made from ASP.NET MVC5 Project template in Visual Studio 2013. I have tried to skim fragmented information available across several blogs and websites to try and get a better understanding of the different components.
ASP.NET 5 vs. ASP.NET MVC 6
One of the major confusion that I had when announcements were made for Visual Studio 2015 preview was the difference between ASP.NET 5 and ASP.NET MVC 6. We already had ASP.NET MVC 5 support in Visual Studio 2013, so naming of the new web stack ASP.NET 5 is bound to create confusion. If you head over to the ASP.NET VNext website Microsoft explains, “ASP.NET 5 is a lean .NET stack for building modern web apps. We built it from the ground up to provide an optimized development framework for apps that are either deployed to the cloud or run on-premises. It consists of modular components with minimal overhead, so you retain flexibility while constructing your solutions.”. In the same article a bit further down they explain, “In ASP.NET 5, MVC, Web API, and Web Pages will be merged into a single framework called MVC 6. This merging removes duplication from the framework and makes it easier for you to develop apps that use these programming frameworks. You no longer need to write slightly different code depending on whether you are within an MVC, Web API, or Web Pages context.”. So essentially MVC 6 is the framework on top of ASP.NET 5 stack which supports building MVC, Web API and Web Pages based applications. The older Web Forms applications are also supported and the Web Forms framework version is now 4.6. I do not remember earlier there be a name for the stack, but it seems now the are naming the stack of technologies as ASP.NET 5 as well as the frameworks separately it really is going to cause confusion for some time.
Creating ASP.NET 5 Web Application Project
Fire up Visual Studio 2015 Preview and click File menu –> Add new Project to bring up the New Project Dialog. Select the ASP.NET Web Application template under Visual C# –> Web as shown in figure 1 below.
Enter the location to create the project as well as the name of the project and solution and click OK. I have kept default names since the purpose for us is to determine the contents of the project items rather than its naming in the blog. The next dialog brings up the selection of the type of ASP.NET project you want to create this is similar to the dialog introduced in Visual Studio 2013. If you select MVC or Web API then it will create a project in older Visual Studio 2013 compatible project format. Our goal in this blog is to explore the new ASP.NET 5 project template, so select the ASP.NET 5 Starter Web template and click OK to create the project. You will see that unlike older MVC or Web API projects where you had a selection of Add folders and core references for to select support for Web Forms, MVC or Web API needed in your project, this option is grayed out since ASP.NET 5 unifies all these into a single project.
Figure 2: New ASP.NET Project dialog
Understanding the different parts of ASP.NET 5 Project
Once the new ASP.NET 5 Web application project is created lets look at the Solution Explorer window to get a better idea of the different components of the new project template.
As you can see from figure 3 above there are a lot of new items in the project structure which did not exist before, lot of familiar items like web.cofig, global.asax etc. are totally missing. Let’s try to go step by step and try to understand the different parts of this project template.
Global.json – Solution Item
Starting from the top of the list we see that under the solution there is a project called as Solution Items which contains a single file called global.json. If you open the file file it has the code as shown in listing 1 below.
{ "sources": [ "src", "test" ] }
Listing 1: global.json file
Something obvious that jumps out is that Microsoft is now trying to shift all configuration information into json file formats so that its easier for other tools to work along with ASP.NET on different platforms. The global.json file is used to mange project to project dependencies. Its useful when there are multiple projects in your solution file then visual studio uses this file to determine dependencies amongst the different projects within the solution. By default, project-to-project references lookup will use parent directory, plus the global.json-defined directories. In code listing 1 above two locations for sources property are defined as src and test. The recommendation is to keep all the source code projects under the src folder and test related projects under the test folder for easier separation which did not exist before. Using the global.json file you can easily reference projects which are not contained within the same solution folder.
As you can see that src folder has been defined as a folder for keeping sources, various projects that you add will be added under the src folder on the physical disk. If you refer back to Figure 3 you will see that our project file WebApplication1 is also contained within the parent src folder.
wwwroot folder
The next item under the Project folder is the wwwroot folder. The wwwroot folder is new in ASP.NET 5 to store all of the static files in your project. Any files including HTML files, CSS files, image files, and JavaScript files which are sent to the users browser should be stored inside this folder. Code files should be placed outside of wwwroot including C# files and Razor views. Having a wwwroot folder keeps a clean separation between code files and static files, it brings clarity to the items that will be sent to the server and the items that should remain on the dev machine. If you look at figure 3 above wwwroot folder has css and lib sub folders. Css folder is a place to keep your custom css files, while lib folder is used by Bower package manger (more on it later). The lib folder contains the packages downloaded by Bower and can contain css,js and images. Figure 3 above shows that lib folder has a bootstrap package folder, if you expand it you will find css, js as well all other assets related to the boostrap package. In MVC4 we used the content folder to keep style sheets as well as scripts folder for referenced scripts, these folders are gone now. So its important to understand that there is no single folder for style sheets or scripts. the could be in any of the folders within wwwroot. Its interesting to note that if you wish to reference the css,js or img files in your razor views, using the ~ keyword ensures direct path to the wwwroot folder. So support you wanted to reference site.css in your view you can access it using the <link rel="stylesheet" href="~/css/site.css" /> syntax. You can see that the ~ keyword points to the wwwroot folder.
Dependencies
The next item you see in the Solution Explorer is Dependencies. This is a new item added in Visual Studio 2015, to support two new open source package managers Bower and NPM. This article from ASP.NET give a good idea on how to use and configure Bower and NPM in detail.
NPM
NPM called the Node Package manager was created to be the package manager for NodeJS framework and is quite popular. Visual Studio 2015 has built capabilities to invoke NPM and install its packages. A lot of current open source tools are distributed via NPM, so having it right within Visual Studio makes it pretty easy for Web Developers to get the best of both worlds, a rich content editing experience as well as access to the latest top rated open source web libraries. The solution contains package.json file which is used to maintain the list of NPM packages and their versions. The default package.json files is listed in listing 2 below.
{ "version": "0.0.0", "name": "WebApplication1", "devDependencies": { "grunt": "^0.4.5", "grunt-bower-task": "^0.4.0" } }
Listing 2: package.json – configration file for NPM
Listing 2 above shows that two NPM packages are configured right now grunt and grunt-bower-task along with their version numbers. Visual Studio shows intellisense in the editor for the name as well as version number of packages. You can directly edit the package.json file to add new packages from NPM and Visual Studio will automatically download and make it available for your project.
Bower
Bower is built on top of NPM and is used as a package manager for client side libraries. So any external client (browser) side resource like bootstrap, requirejs, angularjs should be installed via bower. This replaces the function of NuGet package manager which was used earlier to install all packages in Visual Studio for all client side libraries. NuGet package manager still exists, but the recommendation is to use it for only server side libraries. This decision is bound to create a lot of confusion with existing applications being migrated to ASP.NET 5 having all their packages coming from NuGet. The bower.json file in the solution contains the configuration for bower, listing 3 below shows the default configuration for bower.
{ "name": "WebApplication1", "private": true, "dependencies": { "bootstrap": "~3.0.0", "jquery": "~1.10.2", "jquery-validation": "~1.11.1", "jquery-validation-unobtrusive": "~3.2.2" }, "exportsOverride": { "bootstrap": { "js": "dist/js/*.*", "css": "dist/css/*.*", "fonts": "dist/fonts/*.*" }, "jquery": { "js": "jquery.{js,min.js,min.map}" }, "jquery-validation": { "": "jquery.validate.js" }, "jquery-validation-unobtrusive": { "": "jquery.validate.unobtrusive.{js,min.js}" } } }
Listing 3: bower.json – Bower configuration file
Listing 3 above shows that by default bower.json file has 4 dependencies Bootstrap, jQuery, jQuery Validation and jQuery Unobtrusive Validation with their respective version numbers. Visual Studio has intellisense for editing Bower.json file too and it list the package names and their versions. Once new packages are added Visual Studio will download and make them available for your project.
References
The next section in the Solution Explorer is the all familiar references section. Here all server side assemblies referenced in the project or added via NuGet are displayed. Although if you expand the references and the entries within it you will find that lot of changes have been made under the hood.
NuGet
Now you can see that references are grouped so if your referenced NuGet package depends on several others then they get nested within (unless they are being directly used). You can also create commonly used reusable code as NuGet package and reference it. The NuGet packages are managed from the dependencies section in the project.json file. Visual Studio has also updated the UI for the package manager look at figure 4 below.
Figure 4: NuGet package manager
As you can see from figure 4 the interface for the package manager is changed. The tree view for Installed, Available and Upgrade packages has been removed in favor of a Filter for the packages. Plus whole lot more details about a package are shown as well as their dependencies are clearly listed in the details view. One of the biggest issue that I see right now is that there is no clarity if the package is ASP.NET 5 compatible or not. Or to be more precise if the package contains only server side code or server and client side libraries. Today nothing stops a developer to shoot themselves by trying to install a client library like Bootstrap from nuget. Although the project folder structure has changed installing a client package succeeds but it fails when you try to build the project. There needs to be a clear way to understand which libraries are safe for ASP.NET v5 and which are not. Unless MS does this clear distinction there is bound to be a lot of developer frustration. Expecting that the developer will know about the client library support just looking at the list of dependencies seems to be a mistake.
Controllers, Models, Migrations and Views
These folders remain the same and their contents have only been updated to reflect MVC6 patterns.
Config.json
The infamous XML based web.config file has been dumped in favor of config.json which tries to only focus on keeping configuration values for the project. Config.json is also a standard way to store properties in NPM. So here too Microsoft has made a major change removing the XML based configuration file in favor of json formatted standard file. Listing 4 below shows the standard syntax for the config.json file.
{ "Data": { "DefaultConnection": { "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=aspnet5-WebApplication1-671e15dd-8d5b-45b2-b8a4-0ca00a36cd8c;Trusted_Connection=True;MultipleActiveResultSets=true" } }, "EntityFramework": { "ApplicationDbContext": { "ConnectionStringKey": "Data:DefaultConnection:ConnectionString" } } }
Listing 4: config.json file
As you can see the listing above shows configuration for the database connection string used by Entity Framework as well as the second setting of pointing entity framework to the default connection string.
gruntfile.js – Grunt
Just like Bower, Grunt too is a package manager that depends on NPM, but its used to run tasks and automate tasks on the client side. It can automate tasks like generating css files from less files as well as several other client side optimizations. This article provides information on how to configure and run Grunt tasks. Gruntfile.js is used to define tasks that will be run. Visual Studio has added the integration to be able to integrate Grunt with the visual studio build process so that before or after a build Grunt tasks can be invoked to perform client side tasks before the build can viewed in the browser. Listing 5 below shows the default gruntfile.js code.
// 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({ 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"]); // The following line loads the grunt plugins. // This line needs to be at the end of this this file. grunt.loadNpmTasks("grunt-bower-task"); };
Listing 5: gruntfile.js – grunt tasks
As you can see there is a single task defined i.e. to install Bower plug-ins in the wwwroot/lib directory.
project.json – Project configuration
The last file left to discover is the project.json file. This file contains several configuration information, parts of things which could be configures via the web.config file has been broken into config.json and project.json files. Although I believe web.cofig file could still be used if you were migrating an existing project. This article gives a better description of the various configuration sections within the project.json file. Also as discussed earlier this file holds the NuGet packages as well as version information too. Listing 6 below shows the default project.json file.
{ /* Click to learn more about project.json http://go.microsoft.com/fwlink/?LinkID=517074 */ "webroot": "wwwroot", "version": "1.0.0-*", "dependencies": { "EntityFramework.SqlServer": "7.0.0-beta1", "EntityFramework.Commands": "7.0.0-beta1", "Microsoft.AspNet.Mvc": "6.0.0-beta1", //"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-beta1", "Microsoft.AspNet.Diagnostics": "1.0.0-beta1", "Microsoft.AspNet.Diagnostics.Entity": "7.0.0-beta1", "Microsoft.AspNet.Identity.EntityFramework": "3.0.0-beta1", "Microsoft.AspNet.Security.Cookies": "1.0.0-beta1", "Microsoft.AspNet.Server.IIS": "1.0.0-beta1", "Microsoft.AspNet.Server.WebListener": "1.0.0-beta1", "Microsoft.AspNet.StaticFiles": "1.0.0-beta1", "Microsoft.Framework.ConfigurationModel.Json": "1.0.0-beta1", "Microsoft.Framework.CodeGenerators.Mvc": "1.0.0-beta1", "Microsoft.Framework.Logging": "1.0.0-beta1", "Microsoft.Framework.Logging.Console": "1.0.0-beta1", "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-beta1" }, "commands": { /* Change the port number when you are self hosting this application */ "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000", "gen": "Microsoft.Framework.CodeGeneration", "ef": "EntityFramework.Commands" }, "frameworks": { "aspnet50": { }, "aspnetcore50": { } }, "exclude": [ "wwwroot", "node_modules", "bower_components" ], "packExclude": [ "node_modules", "bower_components", "**.kproj", "**.user", "**.vspscc" ], "scripts": { "postrestore": [ "npm install" ], "prepare": [ "grunt bower:install" ] } }
Listing 5: project.json file
Listing 5 above shows the various sections as well as pre configurations of the project.json file where it defines a wide array of settings from project version to project dependencies.
Conclusion
In the blog post I have tried to cover some of the essential changes that have happened in Visual Studio 2015 Preview ASP.NET 5 project. Microsoft has put a strong emphasis on utilizing the power of open source tools and providing an integrated experience. The have gone to the extant of marginalizing their own NuGet packager manager in favor of open source npm for a wide array of uses. In the process they have added a lot of confusion for new developers who need to know where to utilize which package manager as well as existing projects being migrated to ASP.NET v5 too will need a lot of refactoring to conform to the later standards.