Why you should (almost) always choose an off-the-shelf grid and not build your own.

July 30, 2016

Recently I was in a situation with a whole lot of people who I think should know better. We were building an application and I was not there when the questionable decision was made to build their own grid.

There are a whole swag of reasons, except in the simplest of cases, why you should never build your own grid. Grids can be complicated, and they can require a significant investment to obtain even the simplest of features that you would otherwise get in an off-the-shelf product.

Features like sorting, filtering, frozen columns, frozen rows, summing, hierarchies, cell editing, data exporting, pagination etc. For high volume data, they also include virtual paging, which loads data into the grid page by page, instead of all at once. They can be styled however you want them, and they are fully tested. Sure, they can require a little bit of learning to achieve what you need, but the cost of doing this is significantly less than the build your own solution. The only time you run into problems is when there is too much bloat, or you are trying to do too much with the grid, a problem you would probably have regardless of which path you took.

But you don’t need to believe my opinion. It is a principle of Domain Driven Design. Eric Evans, the original author of Domain Driven Design has a Domain Driven Design Navigation Map which clearly states “Avoid over-investing in generic sub-domains.”

A grid is a perfect example of a generic sub-domain. From Eric’s Diagram:

domain driven design navigation map - generic subdomain

So next time someone is absolutely adamant that they need to build their own grid, see through that for what it is, especially if they claim to be Domain Driven Design experts.


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 10)

July 25, 2016

There’s a new feature called Tag Helpers. They are attributes that you add that help clean up the html tags. They are actually executed just like yellow code, on the server. I’m going to set up a simple one to show redirection to a separate page.

  1. In the Home folder, add a new MVC View Page called Detail.cshtml. This will simply display the details for a single Hotel. Add the following code:
    @model MyFirstAspNetCoreApp.Models.Hotel
    
    <html>
    <head>
        <title>Home</title>
    </head>
    <body>
    <h1>Welcome!</h1>
        @Model.Id <br/>
        @Model.DisplayName
    </body>
    </html>
    
  2. Now we need to add a method to the Home Controller so that knows about the Detail page. In the Home Controller, add the Detail method, as follows:
    using Microsoft.AspNetCore.Mvc;
    using MyFirstAspNetCoreApp.Services;
    using System.Linq;
    
    namespace MyFirstAspNetCoreApp.Controllers
    {
        public class HomeController : Controller
        {
            private IHotelDataService hotelData;
    
            public HomeController(IHotelDataService hotelData)
            {
                this.hotelData = hotelData;
            }
            public IActionResult Index()
            {
                var model = hotelData.GetAll();
                return View(model);
            }
    
            public IActionResult Detail(int id)
            {
                var model = hotelData.GetAll().First(h => h.Id == id);
                return View(model);
            }
    
        }
    }
    

    Note that I’ve cheated a little with the use of First in the LINQ above. It’s a sample app and I need to keep it as simple as possible.

  3. Next we need to add a Tag Helper dependency to our project. Right-click on references and select the Nuget Package Manager. Choose browse and in the search box type TagHelpers. Select the Microsoft.AspNetCode.Mvc.TagHelpers package, install the latest version and blindly accept the licence. After installing the package, there will now be an extra dependency in the project.json file for the newly installed package.
  4. There is a new type of file you can use in Asp.Net now called a View Imports file. That file is called _ViewImports.cshtml. You can add import statements to that file and they will be imported by every file in that folder or in any subfolders. Right-click on the Views folder, and add a new MVC View Imports Page called _ViewImports.cshtml (the default.)
  5. Inside the _ViewImports.cshtml file I add the following line of code, which tells the application that I will be using all the tags in the current assembly:
    @addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"
    
  6. Now, to keep things simple, I am going to change the DisplayName being presented in the Home Index.cshtml page to a link. In the Home Index.cshtml, I change the contents of the li tag as follows:

    @model IEnumerable<MyFirstAspNetCoreApp.Models.Hotel>
    
    <html>
    <head>
        <title>Home</title>
    </head>
    <body>
        <h1>Welcome!</h1>
        <ul>
            @foreach (var hotel in Model)
            {
            <li>
                <a asp-controller="Home" asp-action="Detail" asp-route-id="@hotel.Id">@hotel.DisplayName</a>
            </li>
            }
        </ul>
    </body>
    </html>
    

    Interestingly, you don’t actually need to specify the asp-controller tag if that’s the controller you are currently in. Also, this doesn’t mean that the old ActionLink methods aren’t still available. The following line would still work, it just doesn’t look as aesthetically appealing:

    @Html.ActionLink(@Model.Id.ToString(), "Detail", new { id = Model.Id })
    
  7. Run the application (F5) and when you hover over the links, you should see the last argument (id) change in the link. Click on one of the links, and you should see the details of that link displayed on the Detail page.

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 8)

July 23, 2016
  1. To change it to a list of hotels, the first thing I want to do is set up a dummy data source for the hotels. That’s because I’m not actually getting the data from a database. I want to be able to switch the code over to a database at a later stage, and I don’t want the application to know when I do that. This is important for later, as it is this concept that allows us to independently unit test components.
  2. I have added a HotelDataService class to a Services folder at the top level of my Solution:
    my-first-asp-net-core-app-folder-structure-3x
  3. Inside the HotelDataService, I have the following code:
    namespace MyFirstAspNetCoreApp.Services
    {
        public interface IHotelDataService
        {
            IEnumerable<Hotel> GetAll();
        }
    
        public class DummyHotelData : IHotelDataService
        {
            IEnumerable<Hotel> hotels;
            public DummyHotelData()
            {
                hotels = new List<Hotel>
                {
                    new Hotel { Id = 1, DisplayName = "Sofitel" },
                    new Hotel { Id = 2, DisplayName = "Westin" },
                    new Hotel { Id = 3, DisplayName = "Novotel" }
                };
            }
    
            public IEnumerable<Hotel> GetAll()
            {
                return this.hotels;
            }
        }
    }
    
  4. By using an interface, we can separate the source of data from the delivery of that data.
  5. Next, we need to tell the application that this is a service to be injected into a page. And we need to tell it that the data that we want for now is the Dummy Hotel Data. That’s done back in the Startup class, in the ConfigureServices method, as follows:
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddSingleton<IMyCustomConfiguration, MyCustomConfiguration>();
        services.AddSingleton(implementationFactory => Configuration);
    
        services.AddScoped<IHotelDataService, DummyHotelData>();
    }
    

    Note the AddScoped method. This tells the application that each http request should get its own instance of that service, whatever the IHotelDataService supplies, which in this case is DummyHotelData.

  6. Back in the controller, the hotel data service can now by injected via the constructor. Remember, that’s the pattern with dependency injection now:
    namespace MyFirstAspNetCoreApp.Controllers
    {
        public class HomeController : Controller
        {
            private IHotelDataService hotelData;
    
            public HomeController(IHotelDataService hotelData)
            {
                this.hotelData = hotelData;
            }
            public IActionResult Index()
            {
                var model = hotelData.GetAll();
                return View(model);
            }
        }
    }
    

    See the addition of the HomeController constructor, with the hotel data service interface? The application understands that it needs to look up the list of services to obtain an instance from IHotelDataService. It is stored in a local variable that can then be used on the page.
    The model is then set to retrieve the data from the data source on line 13.

  7. Finally, I update the Index.cshtml page to strongly type the IEnumerable and also to display the entire list of hotels:
    @model IEnumerable<MyFirstAspNetCoreApp.Models.Hotel>
    <html>
    <head>
        <title>Home</title>
    </head>
    <body>
        <h1>Welcome!</h1>
        <ul>
            @foreach (var hotel in Model)
            {
            <li>
                @hotel.DisplayName
            </li>
            }
        </ul>
    </body>
    </html>
    

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

July 23, 2016
  1. Controllers should inherit from a Controller base class. This will give you a significantly enhanced set of features related to being a controller.
  2. Go into the HomeController class and change it to inherit from Controller:
    public class HomeController : Controller
    
  3. You should have a formal way to encapsulate the decision of a controller. As a result of this, instead of returning a string from the Index() method, I decided to return a View of a model I created.
  4. At the top level I added a Models folder, and I have added a Hotels.cs class file to that. I have added the following code:
    namespace MyFirstAspNetCoreApp.wwwroot.Models
    {
        public class Hotel
        {
            public int Id { get; set; }
            public string DisplayName { get; set; }
        }
    }
    
  5. Next, I changed my Index action method to return the new View complete with model, as follows:
    public class HomeController : Controller
    {
       public IActionResult Index()
       {
          var model = new Hotel { Id = 1, DisplayName = "Hilton" };
          return View(model);
       }
    }
    
  6. Next, add a Views folder to the solution at the top level of the folder structure, and add an Index.cshtml file to that folder.
  7. As an aside, it looks like Microsoft have decided that the best place for all these MVC folders is at the top level of the project folder structure. I never would have guessed that. But if you don’t have an Index.cshtml file and you run the application, it will tell you where it is attempting to look in /Views/Home/ for the Index.cshtml file. I initially tried to put this under wwwroot, and it couldn’t find it. I put it at the top level of the project and it found it. I have since moved everything to the top level. As  a result, my wwwroot folder is now empty! My solution is now looking like this:
    my-first-asp-net-core-app-folder-structure-2
    Oh well, its all a learning experience!
  8. When moving the folders above to the root level, remember to remove the .wwwroot. from the namespaces.
  9. In the Index.cshtml folder, I have added the following:
    <html>
    <head>
        <title>Home</title>
    </head>
    <body>
    <h1>Welcome!</h1>
    <div>The hotel name is: @Model.DisplayName</div>
    </body>
    </html>
    
  10. Run the application (F5), and see the result. The Hotel name is displayed in the browser.
    my-first-asp-net-core-app-hotel-name
  11. The model is currently not strongly typed in the cshtml page. If you want to strongly type the model, you need to tell Index.cshtml what the type of the model is. Add the following to the top of the file:
    @model MyFirstAspNetCoreApp.Models.Hotel
    
  12. When you do this, any time you reference Model on the page, it should invoke intellisense and show you all the other options available on the Hotel object. Note that it is no longer in the wwwroot namespace as I’ve moved it to the root folder of the project and renamed the namespace.
  13. Next I will return a list of Hotels.