ASP.NET Core 1.0 – How to install gulp

July 31, 2016

In a previous blog post, I installed npm, otherwise known as the node package manager. I added an npm configuration file under the wwwroot folder called package.json. There are two problems with this. Firstly, Visual Studio Dependencies haven’t been designed for that scenario, which means adding npm packages won’t update the Dependencies folder at the root level, so you lose a fair bit of control over the packages installed. Secondly, the nature of npm is that there could be a whole bunch of additional files added to the package that could be unrelated to the runtime needs of the package. Having these files added could potentially create a risk.

Now, to approach a better practice, I have decided to go back to putting the packages in the root folder. I right-clicked on the project, add new item, and then selected an npm configuration file, then add. This adds the package.json back into the root folder. I then copied the contents of the original package.json I had under wwwroot into the package.json file in the root folder. After this, I deleted the package.json file from the wwwroot folder and deleted the entire node_modules folder. Why did I do this? Because that is what the state of the folder would have been like under the default scenario of installing npm packages at the top level.

Now, given that any static files that are served to the web site need to reside under wwwroot, I had to come up with a way to relocate the contents of node_modules under wwwroot that didn’t involve putting the package.json file there.

While the most common way to do this was simply to add a static file provider to the Startup.cs file, in the configure method, as the following code demonstrates

 app.UseStaticFiles(new StaticFileOptions
      {
           FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "node_modules")),
           RequestPath = "/node_modules"
      });

I decided that eventually I will want a lot more control over this.

Well, the way of the future is to use a tool like gulp, which enables you to run tasks via the Task Runner Explorer in Visual Studio 2015.

Now, I have to admit that I have been attempting to get Angular 2 running in Visual Studio Core 1.0, with some success. That will be the subject of a future post. But for now, I have added gulp into the npm package.json file. That now likes like this:

{
  "version": "1.0.0",
  "name": "myfirstaspnetcoreapp",
  "private": true,
  "devDependencies": {},
  "dependencies": {
    "@angular/common": "2.0.0-rc.4",
    "@angular/compiler": "2.0.0-rc.4",
    "@angular/core": "2.0.0-rc.4",
    "@angular/http": "2.0.0-rc.4",
    "@angular/platform-browser": "2.0.0-rc.4",
    "@angular/platform-browser-dynamic": "2.0.0-rc.4",
    "@angular/router": "3.0.0-beta.2",
    "bootstrap": "^3.3.7",
    "core-js": "^2.4.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.6",
    "systemjs": "0.19.27",
    "zone.js": "^0.6.12",
    "gulp": "^3.9.1",
    "rimraf": "^2.5.4"
  }
}

At the bottom of this file are references to gulp and rimraf. Rimraf is the package for doing the unix equivalent of an rm -rf. Gulp is needed to support gulp in the Task Runner Explorer.

Next I added the gulp configuration file to the top level of my project. Right click on MyFirstAspNetCoreApp and click Add New Item, then select Gulp Configuration File. The Gulp Configuration File is a javascript file called gulpfile.js. Keep that name and click Add.

Open up gulpfile.js, and paste in the following code:

var gulp = require("gulp"),
    rimraf = require("rimraf");

var paths = {
  webroot: "./wwwroot/",
  node_modules: "./node_modules/"
};

paths.libDest = paths.webroot + "node_modules/";

gulp.task("clean:node_modules", function (cb) {
  rimraf(paths.libDest, cb);
});

gulp.task("copy:node_modules", ["clean:node_modules"], function () {

  var node_modules = gulp.src(paths.node_modules + "/**")
                    .pipe(gulp.dest(paths.libDest + ""));

  return node_modules;
});

What this code does is copy the entire nested contents of node_modules in the root folder to node_modules under wwwroot. Now, I wouldn’t ordinarily finish here, as you really should be more specific about the content you’re actually copying. But to keep it simple, I have settled on this for now.

Next, open up the Task Runner Explorer. If you can’t see it at the bottom of your screen, it is found under View > Other Windows > Task Runner Explorer.

After building my app, the task runner explorer looks like this for me.

asp-net-core-task-runner-explorer

Now I can right-click on the copy:node_modules task and click Run. If you notice in gulpfile.js, there is a dependency on clean:node_modules, so that will run clean as well. You shouldn’t need to run this every time you compile the application. You only need to run this when adding and removing npm packages. Nothing changes in the meanwhile.

Now, when you you go to wwwroot and Show All Files, you should see the node_modules folder has been copied.

The files within node_modules are now available to be added into your html.


ASP.NET Core 1.0 – How to install npm

July 28, 2016

npm is a package manager that installs, publishes and manages node programs.

To install it in an ASP.NET Core 1.0 Visual Studio 2015 application, Right-Click on the wwwroot folder, Add a New Item, then click on Client Side in the left nav, and select npm Configuration File and click Add. It will add the default package.json file to the project.

Within the package.json file, change the name attribute to something specific to your application. In my case, I named it “myfirstaspnetcoreapp.” Must be lowercase, it seems to accept spaces but I have avoided them.

By default the attribute name is set to “asp.net”. If you don’t change the name, the Dependencies folder won’t get generated. The Dependencies folder is where the npm packages are referenced.

To add bootstrap to my project, I need to add a dependencies attribute group, and specify the package and version number. Here is my package.json file:

{
  "version": "1.0.0",
  "name": "myfirstaspnetcoreapp",
  "private": true,
  "devDependencies": {
  },
  "dependencies": {
    "bootstrap": "^3.3.7"
  }
}

Note the hat/carat character in the version number for bootstrap. That means give me the latest version 3 package greater than or equal to 3.3.7 but less than version 4.

The moment you save this file, bootstrap will be loaded and you will see the bootstrap package referenced under the Dependencies > npm folder.

The files themselves will be installed at the root level of the wwwroot folder under a node_modules folder, but that folder will be hidden. You can find it by clicking on the Show All Files icon at the top of Solution Explorer.

asp-net-core-show-all-files

Note that a lot of people install the package.json file at the top level of the project. The problem with that is that only files installed under wwwroot are able to be served to the web site. To get around that, those people have to either use gulp to relocate the package files as a post build step, or they use another UseStaticFiles statement in the Startup Configure method and supply the alternative folder in the options collection.

The method I am using seems a bit cleaner to me, so unless someone can tell me why I shouldn’t do this, I’m going with this method.

Now if you build and run the application, you should be able to go directly to the file and it will be served to you:

http://localhost:3858/node_modules/bootstrap/dist/css/bootstrap.css

Because of this, you will now be able to reference the stylesheet from within your header:

<html>
<head>
  <title>Home</title>
  		<link href="/node_modules/bootstrap/dist/css/bootstrap.css" rel="stylesheet" />
</head>

Bootstrap has been around for a long time, so I won’t go into how bootstrap works. By default bootstrap works off a division of horizontal screen space into 12 columns. Here I have put a little bit of styling on one of my pages. col-md-6 is a 6 column division for a medium screen size (to become responsive, you can specify in the same class tags a different number of columns for a different target screen size).

@using System.Security.Claims
@model MyFirstAspNetCoreApp.Entities.Hotel

<html>
<head>
  <title>Detail</title>
  	<link href="/node_modules/bootstrap/dist/css/bootstrap.css" rel="stylesheet" />
<style>
    .col-md-6 {
      border: 2px solid black;
    }
  </style>

</head>
<body>
<h1>Welcome!</h1>
@if (User.Identity.IsAuthenticated)
  {
<div class="row">
<div class="col-md-12">@User.Identity.Name</div>
</div>
<div class="row">
<div class="col-md-12">
<form method="post" asp-controller="Account" asp-action="Logout">
          <input type="submit" value="Logout" />
        </form></div>
</div>
}
  else
  {
<div class="row">
<div class="col-md-6">
        <a asp-controller="Account" asp-action="Login">Login</a></div>
<div class="col-md-6">
        <a asp-controller="Account" asp-action="Register">Register</a></div>
</div>
}
<div class="row">
<div class="col-md-6">@Model.Id</div>
<div class="col-md-6">@Model.DisplayName</div>
</div>
</body>
</html>

String interpolation in Asp.Net MVC

July 25, 2016

I just came across a reference to string interpolation in Asp.Net MVC. Apparently if you start a string reference with a dollar ($) sign, it will accept curly bracketed arguments, like the following:

@model Hotel
@{
    var mystring = $"The hotel name is:{Model.DisplayName}";
}

This allows you to put the arguments inside the string. It replaces it with the contents of the argument, which in this case is the display name of the hotel.


Notes from building a first ASP.Net Core App (part 9)

July 24, 2016

I now want to connect my application to the database. The Entity Framework has been completely re-written for Dot Net Core. Larger ORMs such as Entity Framework and nHibernate are great ideas, especially with their integration with LINQ, because they allows you to write SQL-like syntax in your middle-tier, instead of manipulating SQL strings. This means that they essentially shift any syntax errors that would normally be found at runtime back to compile time, and anyone that has studied the benefits of discovering bugs earlier in the development life-cycle knows that the earlier you find an error in the process, the cheaper it is to correct.

That’s all well and good, except that the performance price for doing this has sometimes been a factor of 10x. That is, queries that would take 500ms in Entity Framework have taken only 50ms in Dapper, a streamlined, cut down ORM (known as a Micro-ORM), and marginally less with a straight Sql Data Reader (perhaps around 48ms).

So many people, especially people that code for high performance sites, have moved away from Entity Framework and are now using Micro-ORMs, such as Dapper.

And as I’ve suggested above, the downside is that Micro-ORMs such as Dapper force us to return to using strings, which returns us to the position of potentially only discovering errors in SQL at runtime. To counteract this, developers must absolutely write a lot of tests to ensure this situation does not occur.

But for now, I want to see how to get the new Entity Framework to work, so I will set up the application to perform some work, then later on perhaps I will run a few tests comparing the new Entity Framework to Dapper.

So next, I need to install Entity Framework Core edition. And I want to configure it for Database First Migrations.

  1. Open up Package Manager Console, and run the following commands:
    Install-Package Microsoft.EntityFrameworkCore.SqlServer
    Install-Package Install-Package Microsoft.EntityFrameworkCore.Tools –Pre
    

    Note the Pre in the second command. That is because the Tools for the Entity Framework Core actually haven’t made it to RTM yet. They are still working on them. But in the meanwhile, we can still use the pre-release version. The Tools part is what gives us Migrations in the Package Manager Console.

  2. Some modifications are needed to the project.json file. Make the following additions to the project.json file, found in the root folder.
    {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "version": "1.0.0",
          "type": "platform"
        },
        "Microsoft.AspNetCore.Diagnostics": "1.0.0",
        "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
        "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
        "Microsoft.Extensions.Logging.Console": "1.0.0",
        "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
        "Microsoft.Extensions.Configuration.Json": "1.0.0",
        "Microsoft.AspNetCore.StaticFiles": "1.0.0",
        "Microsoft.AspNetCore.Mvc": "1.0.0",
        "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
        "Microsoft.EntityFrameworkCore.Design": {
          "type": "build",
          "version": "1.0.0-preview2-final"
        },
        "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
      },
    
      "tools": {
        "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
        "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
      },
    
  3. Now we need a Database Context object. I created new Folder called DBML in the root of the project, and added a new class called HotelDbContext.
    my-first-asp-net-core-app-folder-structure-4
  4. Inside the HotelDbContext, I have inherited from the Entity Framework’s DbContext class, set up a constructor to pass in options such as the connection string, and made a reference to the Hotels DbSet. This is how EntityFramework knows that the Hotel class is what it wants to generate database objects for.
    namespace MyFirstAspNetCoreApp.DBML
    {
        public class HotelDbContext : DbContext
        {
            public HotelDbContext(DbContextOptions<HotelDbContext> options) : base(options)
            {
            }
            public DbSet<Hotel> Hotels { get; set; }
        }
    }
    
  5. The next task is to create the new Sql Hotel Data Service. We will switch the Hotel Data Service from the Dummy Hotel Data Service to the Sql Hotel Data Service.
    In the services folder, I have created a new IHotelDataService.cs file. I have taken the original IHotelDataService.cs interface and have now put that into the IHotelDataService.cs file, removing it from DummyHotelData.cs. Then I added a new class, which also inherits from IHotelDataService, as SqlHotelData. The Services folder now looks like this:
    my-first-asp-net-core-app-folder-structure-5
  6. Here is the new code for SqlHotelData:
    using System.Collections.Generic;
    using MyFirstAspNetCoreApp.Models;
    using MyFirstAspNetCoreApp.DBML;
    
    namespace MyFirstAspNetCoreApp.Services
    {
        public class SqlHotelData : IHotelDataService
        {
            private HotelDbContext context;
    
            public SqlHotelData(HotelDbContext context)
            {
                this.context = context;
            }
            public IEnumerable<Hotel> GetAll()
            {
                return this.context.Hotels;
            }
        }
    }
    

    Note that the SqlHotelData constructor takes a HotelDbContext object as an argument. This is passed in when the class is instantiated. I have then used that context object to obtain the list of Hotels in the GetAll() method.

  7. Back to configuration, and I have discovered that application settings are now meant to be stored in a file called appsettings.json. It says so in a comment the web.config file. So I have renamed my custom configuration file to appsettings.json.my-first-asp-net-core-app-folder-structure-6
  8. This requires a change in the Startup.cs file. Modify the Startup constructor to point to the correct settings json file:
    public Startup()
    {
        Configuration = new ConfigurationBuilder()
                       .SetBasePath(Directory.GetCurrentDirectory())
                       .AddJsonFile("appsettings.json")
                       .Build();
    }
    
  9. While we’re here, we may as well set the data context and redirect from the Dummy data source to the Sql data source. In the Configure Services method, comment out the old Dummy line and introduce the new Sql line:
    public void ConfigureServices(IServiceCollection services)
    {
       services.AddMvc();
       services.AddSingleton<IMyCustomConfiguration, MyCustomConfiguration>();
       services.AddSingleton(implementationFactory => Configuration);
    
       //services.AddScoped<IHotelDataService, DummyHotelData>();
       services.AddScoped<IHotelDataService, SqlHotelData>();
    }
    
  10. Now the reason I needed to fix up the appsettings file was that this is where I want to add in the database connection string. Go to the appsettings.json file and add a new connection string for the Hotel Database.
    {
      "my-custom-message": "The quick brown fox!",
      "ConnectionStrings": {
        "HotelDatabaseConnection" :  "Data Source=(localdb)\\mssqllocaldb;Initial Catalog=MyHotel"
      }
    }
    
  11. To wire this up and add the DbContext in, go back to the ConfigureServices method and add a services.AddDbContext line, as follows:
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddSingleton<IMyCustomConfiguration, MyCustomConfiguration>();
        services.AddSingleton(implementationFactory => Configuration);
    
        services.AddDbContext<HotelDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("HotelDatabaseConnection")));
        //services.AddScoped<IHotelDataService, DummyHotelData>();
        services.AddScoped<IHotelDataService, SqlHotelData>();
    }
    
  12. Now for the fun bit: Migrations. Because we’ve installed the Entity Framework Core tools and added the “Microsoft.EntityFrameworkCore.Design” dependency in the project.json file, we should now be able to run the migrations from the Package Manager Console window. Open up the Package Manager Console and type:
    Add-Migration MyFirstMigration
    

    If successful, it should show the line “To undo this action, use Remove-Migration.” If you look in you project, there should now be some generated migration code under a new folder called Migrations. I won’t go into it, but feel free to take a look at this.

  13. Finally, to get he migration to execute, go to the Package Manager Console and enter:
    Update-Database
    

    After a bit, it should respond with “Done.”

  14. Go to the View menu in Visual Studio 2015, and select “SQL Server Object Explorer”
    my-first-asp-net-core-app-sql-server-structure
  15. You should see the results above. But we’re not ready to execute it just yet – there is no data. Right click on the dbo.Hotels table and click View Data. We will insert the data there.
    my-first-asp-net-core-app-sql-server-data-entry
  16. Now run the application (F5), and you should see the new data appear in the browser:
    my-first-asp-net-core-app-updated-data
  17. And that’s it! Hopefully I haven’t missed anything. Post a comment if I have and I’ll try to be responsive and fix it pronto.

Notes from building a first ASP.Net Core App (part 6)

July 23, 2016
  1. I want to create an MVC application. To do this, I’m going to need to add another package and configure it. But I don’t need to install a Nuget package for this, it’s already in the environment. All we need to do is add it to project.json. Add the line of code as follows:
      "dependencies": {
        "Microsoft.NETCore.App": {
          "version": "1.0.0",
          "type": "platform"
        },
        "Microsoft.AspNetCore.Diagnostics": "1.0.0",
        "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
        "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
        "Microsoft.Extensions.Logging.Console": "1.0.0",
        "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
        "Microsoft.Extensions.Configuration.Json": "1.0.0",
        "Microsoft.AspNetCore.StaticFiles": "1.0.0",
        "Microsoft.AspNetCore.Mvc":  "1.0.0"
      },
    

    The save the project.json file, and it will restore what it needs to support MVC within the application.

  2. We need to be able to route to a controller class in MVC. The default controller in MVC is the HomeController. We need to add a HomeController. So create a Controllers folder under wwwroot, and add a HomeController.cs file. asp-net-core-file-system-2
  3. Inside that class, we will need to implement the default action, which is called Index, as follows:
    namespace MyFirstAspNetCoreApp.wwwroot.Controllers
    {
        public class HomeController
        {
            public string Index()
            {
                return "MVC in ASP.Net Core Rocks!";
            }
        }
    }
    
  4. Now we need to wire up the application to intercept the MVC request and serve up the contents of the Index action. In the Startup class, just before the app.Run, add the following line:
    app.UseMvcWithDefaultRoute();
    
  5. If you mouseover that method and display the intellisense,  it says “Adds MVC to the IApplicationBuilder request execution pipeline with a default route named ‘default’ and the following template: ‘{controller=Home}/{action=Index}/{id?}’. This is why the controller needs to be called HomeController, and the method needs to be called Index. Its how the mvc default route pipeline works.
  6. Build and run the application (F5). You should see it display the text from the controller:
    MVC in ASP.Net Core Rocks!
  7. Note that it has terminated the pipeline, and doesn’t continue through to the “Hello World!…” statement.
  8. Now we want to set up the routing. Routing is performed by using the URL to redirect to a controller and action. The controller is a class and the action is a method on that class.
  9. To configure routing, change the app.UseMvcWithDefaultRoute() to this:
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
    
  10. This will be much more familiar to you if you’ve done a fair bit of MVC in the old framework. If you create a new project with ASP.Net Code and select the Web Application template, you will see that this is exactly what is does. Home is a default, Index is a default, and ? is optional.
  11. You can now add any controllers and actions you like, just by adding the controller classes, their actions, and their route mapping, using the same methods above.

Notes from building a first ASP.Net Core App (part 5)

July 23, 2016
  1. Be default, and Empty ASP.Net Core application does not actually serve up html pages. You have to add that to the pipeline.
  2. To prove this, add an html page to the wwwroot folder, run the application and try navigating to the page. It will return the default web site, in the state you last left it in. The html page won’t show.
  3. To get static content to be shown will require the Microsoft AspNet Static Files middleware. This is installed via a Nuget package. Right-Click on the Package Manager, choose Browse, then type static files. Select “Microsoft.AspNetCore.StaticFiles” from the list and install it. Agree the the licence blindly (like you always do.)
  4. Go into the Startup class and add the following pipeline statement:
    app.UseStaticFiles();
    

    Put it just before the app.Run statement.

  5. Run the application, and it will show the site just as before. Navigate to the html page and viola, it renders!
  6. What happens is that when it hits the Static Files middleware, it will look for the file in the file system, and if it finds a static file match, it will render it and return. Otherwise, it will continue through to the app.Run.
  7. This is really important, because without it, you won’t be able to run html, javascript or css files. Your Angular files won’t run!
  8. If you want it to use the standard default files usually associated with a web site, you need to add another piece of middleware just before executing the UseStaticFiles method.
  9. To do that, add UseDefaultFiles method to your code:
      public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IMyCustomConfiguration myCustomConfiguration)
            {
                loggerFactory.AddConsole();
    
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                //app.UseWelcomePage();
                app.UseDefaultFiles();
                app.UseStaticFiles();
    
                app.Run(async (context) =&gt;
                {
                    var newHelloWorldMessage = string.Format("Hello World! Your text was &gt;{0}&lt;", myCustomConfiguration.GetMyCustomMessage());
    
                    await context.Response.WriteAsync(newHelloWorldMessage);
                });
            }
    

    This will now automatically redirect you site to files like default.html, or index.html.

  10. But that’s not all. You don’t actually need those two lines. You can replace them both with:
                //app.UseDefaultFiles();
                //app.UseStaticFiles();
                app.UseFileServer();
    

    which will perform the same job.


Notes from building a first ASP.Net Core App (part 4)

July 23, 2016
  1. ASP.Net Core applications are layered. There is an application pipeline that processes your http requests and responses. This is known as middleware.
  2. The logger factory is a piece of middleware, as is the Developer Exception page.You can find them in the Configure method of the Startup class in Startup.cs.
    loggerFactory.AddConsole();
    
    if (env.IsDevelopment())
    {
    app.UseDeveloperExceptionPage();
    }
    
  3. app.Run is a piece of middleware as well. The context object is similar to the HttpContext object you would be familiar with. It has references to Request and Response objects. app.Run occurs at the end of the pipeline. Nothing after app.Run will be executed, as it does not allow piping into another piece of middleware.
  4. To register your own middleware, you’d add it via the app.Use method. There are some provided by default. There are others you can load from nuget packages.
  5. For example, if you want to add a Welcome Page, you can add the following line just before calling app.Run:
    app.UseWelcomePage();
    

    This provides a default welcome page. If you run the site, there will now be a Welcome Page. There are overrides for this method that will allow you to supply alternative welcome pages. Most pipelines do have overrides to supply configuration.

  6. When you’ve finished with the Welcome Page, comment that line out.
  7. One of the default pipelines available is the Hosting Environment pipeline. It is here that you can query to find out whether you are in development, staging or production, what the Application Name is, what the Content Root Path is, what the absolute Web Root Path is.This is injected via the IHostingEnvironment interface in the Configure method. It knows which environment you are in by looking at the Project’s Environment Variables, which you set from the project’s debug configuration page.
  8. Another one of the default pipelines supplied is the Exception Handling page for developers. Without it, your pages would get an Internal Server Error (status code of 500.)
  9. Go into the app.Run call and add an Exception, as follows:
    app.Run(async (context) =&gt;
    {
        throw new Exception(&quot;What!!!&quot;);
    
        var newHelloWorldMessage = string.Format(&quot;Hello World! Your text was &gt;{0}&lt;&quot;, myCustomConfiguration.GetMyCustomMessage());
    
        await context.Response.WriteAsync(newHelloWorldMessage);
    });
    

    Then run your application. Because of the exception handler pipeline, it will display an Exception page, as follows: asp-net-core-exception
    If you choose to, you can click the “Show raw exception details link” and it will expand and provide a stack trace.