The default Core website with Visual Studio Code
Another entry from my ".NET with Visual Studio Code" series, this will discuss the default web site generated by the 'dotnet new' command. I recommend reading the previous articles:
Update 31 Mar 2017: This entire article is obsolete.
Since the release of .NET Core 1.1 the dotnet command now has a different syntax: dotnet new <template> where it needs a template specified, doesn't default to console anymore. Also, the web template is really stripped down to only what one needs, similar to my changes to the console project to make it web. The project.json format has become deprecated and now .csproj files are being used. Yet I worked a lot on the post and it might show you how .NET Core came to be and how it changed in time.
The analysis that follows is now more appropriate for the dotnet new mvc template in .NET Core 1.1, although they removed the database access and other things like registration from it.
Until now we've used the simple 'dotnet new' command which defaults to the Console application project type. However, there are four available types that can be specified with the -t flag: Console,Web,Lib and xunittest. I want to use Visual Studio Code to explore the default web project generated by the command. So let's follow some basic steps:
So, what do we got here? It seems like an earlier version of John Papa's AspNet5-starter-demo project.
First of all there is a nice README.MD file that announces this is a big update of the .NET Core release and it's a good idea to read the documentation. It says that the application in the project consists of:
If we go to the Debug section of Code and run the web site, two interesting things happen. One is that the project compiles! Yay! The other is that the web site at localhost:5000 is automatically opened. This happens because of the launchBrowser property in build.json's configuration:
The web site itself looks like crap, because there are some console errors of missing files like /lib/bootstrap/dist/css/bootstrap.css, /lib/bootstrap/dist/js/bootstrap.js, /lib/jquery/dist/jquery.js and /lib/bootstrap/dist/js/bootstrap.js. All of these files are Javascript and CSS files from frameworks defined in bower.json:
What is Bower? Apparently, it's a package manager that depends on node, npm and git. Could it be that I need to install Node.js just so that I can compile my C# ASP.Net project? Yes it could. That's pretty shitty if you ask me, but I may be a purist at heart and completely wrong.
While ASP.Net Core's documentation about Client-Side Development explains some stuff about these tools, I found that Rule-of-Tech's tutorial from a year and a half ago explains better how to install and use them on Windows. For the purposes of this post I will not create my own .NET bower and gulp emulators and install the tools as instructed... and under duress. You're welcome, Internet!
Go to the Git web site, and install the client.
Go to the Node.js site and install it. Certainly a pattern seems to emerge here. On their page they seem to offer two wildly different versions: one that is called LTS and has version v4.4.7, another that is called Current at version v6.3.0. A quick google later I know that LTS comes from 'Long Term Support' and is meant for corporate environments where change is rare and the need for specific version support much larger. I will install the Current version for myself.
The Bower web site indicates how to install it via the Node.js npm:
Install Gulp with npm as well:
Before I go into weird Linux reminiscent console warnings and fixes, let's see if we can now fix our web site, so I run "gulp" and I get the error "Task 'default' is not in your gulpfile. Please check the documentation for proper gulpfile formatting". Going back to the documentation I understand why: it's because there is no default task in the gulpfile! Well, it sounded more exciting in my head.
Long story short, the commands to be executed are in project.json, in the scripts section:
It was the bower command that we actually needed to make the web site load the frameworks needed. Phew!
Let's start the web site again, from Code, by going to Debug and clicking Run. (By now it should be working with F5, I guess) Victory! The web site looks grand. It works!
But what is that prepublish nonsense? Frankly, no one actually knows or cares. It's not documented and, to my chagrin, it appears the project.json method of using projects will be phased out anyway! Whaat?
Remember that .NET Core is still version 1. As Microsoft has accustomed us for decades, you never use version 1 of any of their products. If you are in a hurry, you wait until version 2. If you care about your time, you wait for the second service pack of version 2. OK, a cheap shot, but how is it not frustrating to invest in something and then see it "phased out". Didn't they think things through?
Anyway, since the web site is working, I will postpone a rant about corporate vision and instead continue with the analysis of the project.
Not only did I install Node and Bower and Gulp, but a lot of dependencies. The local installation folder for Node.js packages called node_modules is now 6MB of files that are mostly comments and boilerplate. It must be the (in)famous by now NPM ecosystem, where every little piece of functionality is a different project. At least nothing else seems to be polluted by it, so we will ignore it as a necessary evil.
Following the pattern discussed in previous posts, the Program class is building the web host and then passing responsibility for configuration and management to the Startup class. The most obvious new thing in the class is the IConfigurationRoot instance that is built in the class' constructor.
Let me quickly list other interesting things for you to research in depth later:
I've tried to use the most relevant links up there, but you will note that some of them are from spring 2015. There is still much to be written about Core, so look it up yourselves.
As you know, almost any application worth mentioning uses some sort of database. ASP.Net MVC uses an abstraction for that called ApplicationDbContext, which the Microsoft team wants us to use with Entity Framework. ApplicationDbContext just inherits from DbContext and links it to Identity via an ApplicationUser. If you unfamiliar on how to work with EF DbContexts, check out this link. In the default project the database work is instantiated with
Personally I am not happy that with a single instruction I now have in my projects dependencies to
AddDbContext is a way of injecting the DbContext without specifying an implementation. UseSqlite is an extension method that gets that implementation for you.
Let us test the functionality of the site so that I can get to an interesting EntityFramework concept called Migrations.
So, going to the now familiar localhost:5000 I notice a login/register link combo. I go to register, I enter a ridiculously convoluted password pattern and I get... an error:A database operation failed while processing the request.
Applying existing migrations for ApplicationDbContext may resolve this issue
What is all that about? Well, in a folder called Data in our project there is a Migrations folder containing files 00000000000000_CreateIdentitySchema.cs, 00000000000000_CreateIdentitySchema.Designer.cs and ApplicationDbContextModelSnapshot.cs. They inherit from Migration and ModelSnapshot respectively and seem to describe in coade database structure and entities. Can it be as simple as running:
What happened? In the /bin directory of our project there is now a WebApplication.db file which, when opened, reveals it's an SQLite database.
But what about the mysterious button "Apply Migrations"? It generates an Ajax POST call to /ApplyDatabaseMigrations. Clicking it also fixes everything. How does that work? I mean, there is no controller for an ApplyDatabaseMigrations call. It all comes from the line
Pesky little middleware, isn't it?
It is a good idea to install SQLite as a standalone application. Make sure you install both binaries for the library as well as the client (the library might be x64 and the client x86). The installation is brutally manual. You need to copy both library and client files in a folder, let's say C:\Program Files\SQLite and then add the folder in the PATH environment variable. An alternative is using the free SQLiteBrowser app.
Opening the database with SQLiteBrowser we find tables for Users, Roles, Claims and Tokens, what we would expect from a user identity management system. However, only the Users table was used when creating a new user.
The controllers of the application contain the last ASP.Net related functionality of the project, anything else is business logic. The controllers themselves, though, are nothing special in terms of Core. The same class names, the same attributes, the same functionality as any regular MVC. I am not a specialist in that and I believe it to be outside the scope of the current blog post. However it is important to look inside these classes and the ones that are used by them so that we understand at least the basic concepts the creators of the project wanted to teach us. So I will quickly go through them, no code, just conceptual ideas:
So far I've described running the web site through the Debug sidebar, but how do I run the website from the command line? Simply by running
In order to change the default IP and port binding, refer to this answer on Stack Overflow. Long story short, you need to use a configuration file from your WebHostBuilder setup.
However there is a lot of talk about dnx. What is this? In short, it's 'dotnet'. Before version 1 there was an entire list of commands like dnvm, dnu, dnx, etc. You may still install them if you want, but I wouldn't recommend it. As detailed in this document, the transition from the dn* tools to the dotnet command is already in progress.
A large number of concepts have been bundled together in the default "web" project type, allowing for someone to immediately create and run a web site, theme it and change it to their own purposes. While creating such a project from Visual Studio is a breeze compared to what I've described, it is still a big step towards enabling people to just quickly install some stuff and immediately start coding. I approve! :) good job, Microsoft!
- Trying out .NET Core and VS Code - Console Hello World
- ASP.Net Core with Visual Studio Code
- ASP.Net Core Web API with Visual Studio Code
Update 31 Mar 2017: This entire article is obsolete.
Since the release of .NET Core 1.1 the dotnet command now has a different syntax: dotnet new <template> where it needs a template specified, doesn't default to console anymore. Also, the web template is really stripped down to only what one needs, similar to my changes to the console project to make it web. The project.json format has become deprecated and now .csproj files are being used. Yet I worked a lot on the post and it might show you how .NET Core came to be and how it changed in time.
The analysis that follows is now more appropriate for the dotnet new mvc template in .NET Core 1.1, although they removed the database access and other things like registration from it.
Setup
Creating the ASP.Net project
Until now we've used the simple 'dotnet new' command which defaults to the Console application project type. However, there are four available types that can be specified with the -t flag: Console,Web,Lib and xunittest. I want to use Visual Studio Code to explore the default web project generated by the command. So let's follow some basic steps:
- Create a new folder
- Open a command prompt in it (Update: Core has a Terminal window in it now, which one can use)
- Type dotnet new -t Web
- Open Visual Studio Code and select the newly created folder
- To the prompt "Required assets to build and debug are missing from your project. Add them?" choose Yes
So, what do we got here? It seems like an earlier version of John Papa's AspNet5-starter-demo project.
First of all there is a nice README.MD file that announces this is a big update of the .NET Core release and it's a good idea to read the documentation. It says that the application in the project consists of:
- Sample pages using ASP.NET Core MVC
- Gulp and Bower for managing client-side libraries
- Theming using Bootstrap
If we go to the Debug section of Code and run the web site, two interesting things happen. One is that the project compiles! Yay! The other is that the web site at localhost:5000 is automatically opened. This happens because of the launchBrowser property in build.json's configuration:
"launchBrowser" : {
"enabled" : true,
"args" : "${auto-detect-url}",
"windows" : {
"command" : "cmd.exe",
"args" : "/C start ${auto-detect-url}"
},
"osx" : {
"command" : "open"
},
"linux" : {
"command" : "xdg-open"
}
}
The web site itself looks like crap, because there are some console errors of missing files like /lib/bootstrap/dist/css/bootstrap.css, /lib/bootstrap/dist/js/bootstrap.js, /lib/jquery/dist/jquery.js and /lib/bootstrap/dist/js/bootstrap.js. All of these files are Javascript and CSS files from frameworks defined in bower.json:
{and there is also a .bowerrc file indicating the destination folder:
"name": "webapplication",
"private": true,
"dependencies": {
"bootstrap": "3.3.6",
"jquery": "2.2.3",
"jquery-validation": "1.15.0",
"jquery-validation-unobtrusive": "3.2.6"
}
}
{. This probably has to do with that Gulp and Bower line in the Readme file.
"directory": "wwwroot/lib"
}
What is Bower? Apparently, it's a package manager that depends on node, npm and git. Could it be that I need to install Node.js just so that I can compile my C# ASP.Net project? Yes it could. That's pretty shitty if you ask me, but I may be a purist at heart and completely wrong.
Installing tools for client side package management
While ASP.Net Core's documentation about Client-Side Development explains some stuff about these tools, I found that Rule-of-Tech's tutorial from a year and a half ago explains better how to install and use them on Windows. For the purposes of this post I will not create my own .NET bower and gulp emulators and install the tools as instructed... and under duress. You're welcome, Internet!
Git
Go to the Git web site, and install the client.
Node.js
Go to the Node.js site and install it. Certainly a pattern seems to emerge here. On their page they seem to offer two wildly different versions: one that is called LTS and has version v4.4.7, another that is called Current at version v6.3.0. A quick google later I know that LTS comes from 'Long Term Support' and is meant for corporate environments where change is rare and the need for specific version support much larger. I will install the Current version for myself.
Bower
The Bower web site indicates how to install it via the Node.js npm:
npm install -g bower. Oh, you gotta love the ASCII colors and the loader! Soooo cuuuute!
Gulp
Install Gulp with npm as well:
npm install --global gulpHere tutorials say to install it in your project's folder again:
npm install --save-dev gulpWhy do we need to install gulp twice, once globally and once locally? Because reasons. However, I noticed that in the project there is already a package.json containing what I need for the project:
{Gulp is among them so I just run
"name": "webapplication",
"version": "0.0.0",
"private": true,
"devDependencies": {
"gulp": "3.9.1",
"gulp-concat": "2.6.0",
"gulp-cssmin": "0.1.7",
"gulp-uglify": "1.5.3",
"rimraf": "2.5.2"
}
}
npm install --save-devwithout specifying a package and it installs what I need. The install immediately gave me some concerning warnings like "graceful-fs v3.0.0 will fail on node releases >=7.0. Please update to graceful-fs 4.0.0" and "please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue" and "lodash v3.0.0 is no longer maintained. Upgrade to lodash v4.0.0". Luckily, the error messages are soon replaced by a random ASCII tree and if you can't scroll up you're screwed :) One solution is to pipe the output to a file or to NUL so that the ASCII tree of the packages doesn't scroll the warnings up
npm install --save-dev >nul
Before I go into weird Linux reminiscent console warnings and fixes, let's see if we can now fix our web site, so I run "gulp" and I get the error "Task 'default' is not in your gulpfile. Please check the documentation for proper gulpfile formatting". Going back to the documentation I understand why: it's because there is no default task in the gulpfile! Well, it sounded more exciting in my head.
Long story short, the commands to be executed are in project.json, in the scripts section:
"scripts": {There is npm install, there is bower install and the two tasks for gulp: clean and min.
"prepublish": [ "npm install", "bower install", "gulp clean", "gulp min" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
It was the bower command that we actually needed to make the web site load the frameworks needed. Phew!
Let's start the web site again, from Code, by going to Debug and clicking Run. (By now it should be working with F5, I guess) Victory! The web site looks grand. It works!
Exploring the project
project.json will be phased out
But what is that prepublish nonsense? Frankly, no one actually knows or cares. It's not documented and, to my chagrin, it appears the project.json method of using projects will be phased out anyway! Whaat?
Remember that .NET Core is still version 1. As Microsoft has accustomed us for decades, you never use version 1 of any of their products. If you are in a hurry, you wait until version 2. If you care about your time, you wait for the second service pack of version 2. OK, a cheap shot, but how is it not frustrating to invest in something and then see it "phased out". Didn't they think things through?
Anyway, since the web site is working, I will postpone a rant about corporate vision and instead continue with the analysis of the project.
node_modules
Not only did I install Node and Bower and Gulp, but a lot of dependencies. The local installation folder for Node.js packages called node_modules is now 6MB of files that are mostly comments and boilerplate. It must be the (in)famous by now NPM ecosystem, where every little piece of functionality is a different project. At least nothing else seems to be polluted by it, so we will ignore it as a necessary evil.
Program and Startup
Following the pattern discussed in previous posts, the Program class is building the web host and then passing responsibility for configuration and management to the Startup class. The most obvious new thing in the class is the IConfigurationRoot instance that is built in the class' constructor.
public IConfigurationRoot Configuration { get; }Here is the appsettings.json file that is being loaded there:
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
Configuration = builder.Build();
{Later on these configuration settings will be used in code:
"ConnectionStrings": {
"DefaultConnection": "Data Source=WebApplication.db"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(Configuration.GetConnectionString("DefaultConnection"))
);
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
Let me quickly list other interesting things for you to research in depth later:
- App Secrets - built into the configuration instance with
builder.AddUserSecrets();
- Using environment variables to overwrite the ones in the json files - built into the configuration with
builder.AddEnvironmentVariables();
- MVC Routing - used in the app with
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
I've tried to use the most relevant links up there, but you will note that some of them are from spring 2015. There is still much to be written about Core, so look it up yourselves.
Database
As you know, almost any application worth mentioning uses some sort of database. ASP.Net MVC uses an abstraction for that called ApplicationDbContext, which the Microsoft team wants us to use with Entity Framework. ApplicationDbContext just inherits from DbContext and links it to Identity via an ApplicationUser. If you unfamiliar on how to work with EF DbContexts, check out this link. In the default project the database work is instantiated with
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(Configuration.GetConnectionString("DefaultConnection"))
);
Personally I am not happy that with a single instruction I now have in my projects dependencies to
"Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0",Let's go with it for now, though.
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
"Microsoft.EntityFrameworkCore.Sqlite": "1.0.0",
"Microsoft.EntityFrameworkCore.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
}
AddDbContext is a way of injecting the DbContext without specifying an implementation. UseSqlite is an extension method that gets that implementation for you.
Let us test the functionality of the site so that I can get to an interesting EntityFramework concept called Migrations.
So, going to the now familiar localhost:5000 I notice a login/register link combo. I go to register, I enter a ridiculously convoluted password pattern and I get... an error:
A database operation failed while processing the request.
SqliteException: SQLite Error 1: 'no such table: AspNetUsers'.
Applying existing migrations for ApplicationDbContext may resolve this issue
There are migrations for ApplicationDbContext that have not been applied to the database
- 00000000000000_CreateIdentitySchema
In Visual Studio, you can use the Package Manager Console to apply pending migrations to the database:
PM> Update-Database
Alternatively, you can apply pending migrations from a command prompt at your project directory:
> dotnet ef database update
What is all that about? Well, in a folder called Data in our project there is a Migrations folder containing files 00000000000000_CreateIdentitySchema.cs, 00000000000000_CreateIdentitySchema.Designer.cs and ApplicationDbContextModelSnapshot.cs. They inherit from Migration and ModelSnapshot respectively and seem to describe in coade database structure and entities. Can it be as simple as running:
dotnet ef database update(make sure you stop the running web server before you run the command)? It compiles the project and it completes in a few seconds. Let's run the app again and attempt to register. It works!
What happened? In the /bin directory of our project there is now a WebApplication.db file which, when opened, reveals it's an SQLite database.
But what about the mysterious button "Apply Migrations"? It generates an Ajax POST call to /ApplyDatabaseMigrations. Clicking it also fixes everything. How does that work? I mean, there is no controller for an ApplyDatabaseMigrations call. It all comes from the line
if (env.IsDevelopment())which installs the MigrationsEndPointMiddleware. Documentation for it here.
{
...
app.UseDatabaseErrorPage();
...
}
Pesky little middleware, isn't it?
Installing SQLite
It is a good idea to install SQLite as a standalone application. Make sure you install both binaries for the library as well as the client (the library might be x64 and the client x86). The installation is brutally manual. You need to copy both library and client files in a folder, let's say C:\Program Files\SQLite and then add the folder in the PATH environment variable. An alternative is using the free SQLiteBrowser app.
Opening the database with SQLiteBrowser we find tables for Users, Roles, Claims and Tokens, what we would expect from a user identity management system. However, only the Users table was used when creating a new user.
Controllers
The controllers of the application contain the last ASP.Net related functionality of the project, anything else is business logic. The controllers themselves, though, are nothing special in terms of Core. The same class names, the same attributes, the same functionality as any regular MVC. I am not a specialist in that and I believe it to be outside the scope of the current blog post. However it is important to look inside these classes and the ones that are used by them so that we understand at least the basic concepts the creators of the project wanted to teach us. So I will quickly go through them, no code, just conceptual ideas:
- HomeController - the simplest possible controller, it displays the home view
- AccountController and ManageController - responsible for account management, they have a lot of functionality including antiforgery token, forgot the password, external login providers, two factor authentication, email and SMS sending, reset password, change email, etc. Of course, register, login and logoff.
- IEmailSender, ISMSSender and MessageServices - if we waited until this moment for me to reveal the simple and free email/SMS provider architecture in the project, you will be disappointed. MessageServices implements both IEmailSender and ISMSSender with empty methods where you should plus useful code.
- Views - all views are interesting to explore. They show basic and sometimes not so basics concepts of Razor Model/View/Controller interaction like: imports, declaring the controller and action names in the form element instead of a string URL, declaring the @model type for a view, validation summaries, inline code, partial views, model to view synchronization, variable view content depending on environment (production, staging), fallback source and automated testing that the script loaded, bootstrap theming, etc.
- Models - model classes are simple POCOs, but they do provide their occasional instruction, like using annotations for data structure, validation and display purposes alike
Running the website
So far I've described running the web site through the Debug sidebar, but how do I run the website from the command line? Simply by running
dotnet runin your project folder. You can just as well use
dotnet compiled.dll, but you need to also run it from the project root. In the former case, dotnet will also compile the project for you, in the latter it will just run whatever is already compiled.
In order to change the default IP and port binding, refer to this answer on Stack Overflow. Long story short, you need to use a configuration file from your WebHostBuilder setup.
However there is a lot of talk about dnx. What is this? In short, it's 'dotnet'. Before version 1 there was an entire list of commands like dnvm, dnu, dnx, etc. You may still install them if you want, but I wouldn't recommend it. As detailed in this document, the transition from the dn* tools to the dotnet command is already in progress.
Conclusions
A large number of concepts have been bundled together in the default "web" project type, allowing for someone to immediately create and run a web site, theme it and change it to their own purposes. While creating such a project from Visual Studio is a breeze compared to what I've described, it is still a big step towards enabling people to just quickly install some stuff and immediately start coding. I approve! :) good job, Microsoft!
Comments
How do I get the database to work in production? It works in development, but it gives me an error saying 'no such table: AspNetUsers' in production. The users.sqlite file is in both. What am I missing? Thank you in advance!
Susan Liu