August 2016

Volume 31 Number 8

[ASP.NET Core]

Write Apps with Visual Studio Code and Entity Framework

By Alessandro Del | August 2016

Open source and cross-platform development are crucial for Microsoft’s current and future strategies. Many building blocks of the .NET stack have been open sourced, while others have been developed to embrace and support the new strategy. ASP.NET Core 1.0, currently in Release Candidate (RC) mode, is the most recent open source technology for building cross-platform applications for the Web and cloud, running on Linux, Mac OS X and Windows.

ASP.NET Core lets you write Model-View-Controller (MVC) applications with C# and relies on .NET Core (dotnet.github.io), the new open source and cross-platform modular set of runtimes, libraries and compilers—in RC, too. The biggest benefit of ASP.NET Core is that it’s completely independent from any proprietary project system or integrated development environment, which means you can also build an ASP.NET Core application outside of Microsoft Visual Studio, and on OSes different than Windows.

To accomplish this, you use a number of command-line tools to scaffold, build and run applications, while you can use Visual Studio Code for editing. There’s a lot of work in progress yet, so some features might change until it reaches the Release-to-Manufacturing (RTM) milestone. For instance, ASP.NET Core used to rely on the .NET Execution Environment (DNX) and its command-line interface (CLI) to build and manage applications; because ASP.NET Core is built upon .NET Core, DNX will be retired and its CLI will switch to the .NET Core command-line tools for future releases, so keep this in mind if you want to start writing cross-platform Web apps with ASP.NET Core and C#.

This article explains how to create a cross-platform ASP.NET Core Web application that leverages Entity Framework 7 to execute data operations against a database, and how to write code in Visual Studio Code (code.visualstudio.com), which you use on Linux, OS X and Windows. Because the focus is on data, I recommend you read the “.NET Core and Visual Studio Code” document on the official Web site (bit.ly/1PhzoC7). You’ll write several commands based on the DNX environment for consistency with the current RC; keep in mind this will be replaced with commands from the .NET Core CLI once ASP.NET Core turns into RTM.

I’ll point out commands that’ll be replaced where appropriate. I’ll create my sample application using the new Visual Studio Code tool. Visual Studio Code is a sophisticated, multi-language and cross-platform development tool that puts writing code at its center and that has hooks so you can issue build commands. I’m assuming you already have installed Visual Studio Code, Node.js (nodejs.org), SQL Server Express Edition (bit.ly/1PhzoC7) and ASP.NET Core 1.0 RC (get.asp.net/OtherDownloads).

Creating a Sample Database

First, create a database with which to work. You might use an existing database, or you could also define the data model with the Entity Framework Code First approach, but support for code migrations in ASP.NET Core is still in progress and not stable at this time. So you’ll simply create a new database that stores a list of car models and their manufacturers’ names. In SQL Server Management Studio, create a new database called Cars, then write and execute the query shown in Figure 1, which defines a table called Cars, with three columns: Id (primary key and auto-increment), CarModel (of type NVarChar(Max)) and Manufacturer (of type NVarChar(Max)).

Figure 1 Creating a Sample Table

CREATE TABLE [dbo].[Cars](
  [id] [int] IDENTITY(1,1) NOT NULL,
  [CarModel] [nvarchar](max) NOT NULL,
  [Brand] [nvarchar](max) NOT NULL,
CONSTRAINT [PK_Cars] PRIMARY KEY CLUSTERED
(
  [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
  ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Cars] ON
GO
INSERT [dbo].[Cars] ([id], [CarModel], [Brand]) VALUES (1, N'Mustang', N'Ford')
GO
INSERT [dbo].[Cars] ([id], [CarModel], [Brand]) VALUES (2, N'500', N'Fiat')
GO
INSERT [dbo].[Cars] ([id], [CarModel], [Brand]) VALUES (3, N'Giulia', N'Alfa Romeo')
GO
SET IDENTITY_INSERT [dbo].[Cars] OFF
GO
USE [master]
GO
ALTER DATABASE [CARS] SET  READ_WRITE
GO

Depending on your scenario, you might also want to consider a column of type bit that you use to mark an item as deleted but that actually is never removed from the data store physically.

Ensure the database, the table and sample data are properly shown in the Management Studio Object Explorer.

Installing C# for Visual Studio Code

In Visual Studio Code, the C# language support has recently moved to an extension that you must download and install separately. It is strongly recommended you install the C# extension to get all the evolved editing features such as syntax colorization, IntelliSense, code issue detection as you type and much more. In order to install C#, run Visual Studio Code, open the Command Palette (F1), then type “ext install” and press Enter. From the list of extensions, double-click C# and wait for the installation to complete. When prompted, accept to restart Visual Studio Code.

Scaffolding an ASP.NET Core Application

Visual Studio Code has no built-in commands that automate the generation of an ASP.NET Core project and creating a project manually requires some effort. With the current RC of ASP.NET Core, you can use a command-line tool called Yeoman (yeoman.io), a popular scaffolding tool that provides, among other things, an option to generate an ASP.NET Core app skeleton. Yeoman relies on Node.js and must be installed from the command line using the Node.js package manager (npm). That said, open a command prompt and type the following line:

> npm install -g yo generator-aspnet gulp bower

That will install Yeoman (represented by “yo”) in the global location (-g) together with gulp (a tool for task automation) and bower (a client-side library manager). Notice that Yeoman ships with a number of generators, including the ASP.NET generator and the Visual Studio Code extension generator. The generator-aspnet option in the previous command line will download and install the ASP.NET Core generator that will simplify your work. When ready, using the cd (or chdir) command, move into a folder where you want to create a new application (cd C:\temp). At this point, type the following command line:

> yo aspnet

This will open the Yeoman ASP.NET generator, as you can see in Figure 2.

Starting the Yeoman Generator
Figure 2 Starting the Yeoman Generator

Select the Web Application template and press Enter. In the next screen, enter CarModels as the application name and press Enter. The generator defines the application’s root namespace based on the app name casing. As a consequence, if CarModels is the application name, then the root namespace will also be CarModels; but if you enter carmodels or carModels as the app’s name, then your root namespace will be carmodels or carModels, respectively. Take care of this when specifying the application name. After a few seconds, Yeoman completes generating a new ASP.NET Core application into a subfolder called CarModels. With future ASP.NET Core releases, you also will be able to use the .NET Core CLI for scaffolding a Web application. The command line you’ll use will look like this:

> dotnet new

The current version of the CLI doesn’t support scaffolding a Web application, yet; rather, it generates an empty Console application, so this is another reason why you see Yeoman in action here. Enter the CarModels folder by writing “cd CarModels” and then type “code,” so that Visual Studio Code will start up, opening the current folder and its contents. When Visual Studio Code opens a folder, it scans for known project file names, such as project.json, package.json or .sln MSBuild solution files. In the case of an ASP.NET Core project, Visual Studio Code finds project.json, collects dependency information, and organizes code files and subfolders in a proper way. The first time the project is open, Visual Studio Code detects missing NuGet packages and offers to make a Restore for you.

Click Restore on the informational bar and wait for the NuGet packages to be downloaded. When finished, you can leverage all the advanced code-editing features of Visual Studio Code to write and edit code files and reuse most of your existing skills with ASP.NET MVC. In fact, Visual Studio Code not only supports C#, but it also offers syntax colorization and other advanced features for all the file types that compose an ASP.NET Core application, including .cshtml, CSS style sheets, JavaScript and .json files.

Creating the Data Model with Entity Framework 7

Now that you have an empty ASP.NET Core application, the next step is to create a data model with Entity Framework 7, the new version of the popular object-­relational mapper from Microsoft, which offers support for ASP.NET Core. At the time of this writing, Entity Framework 7 is in RC1. Creating the model will be accomplished running the proper dnx commands from the command prompt and involves a couple of NuGet packages. The first NuGet package is called EntityFramework.MicrosoftSqlServer and is auto­matically referenced by the newly created project. The second NuGet package is called EntityFramework.MicrosoftSqlServer.Design and must be added manually to the project dependencies. To do this, in Visual Studio Code open the project.json file and locate the following line within the dependencies node:

"EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final",

After this line, add this:

"EntityFramework.MicrosoftSqlServer.Design": "7.0.0-rc1-final",

Notice that both packages must have the same version number, which will change in future releases. Save project.json. Visual Studio Code will detect a missing NuGet package and will prompt again for a package Restore. As usual, accept its offer.

Now open a command prompt over the folder that contains the ASP.NET Core project. The dnx environment provides the ef command, which lets you generate entity data models from the command line. This command offers additional commands, such as database, dbcontext and migrations. The database command lets you manage a database, dbcontext lets you scaffold a DbContext type and entities, and migrations lets you work with code migrations. You’ll use the dbcontext command to generate a DbContext class and the necessary entities. You can write dnx ef to view the list of available commands (see Figure 3) or type a complete command directly.

List of Available Entity Framework Commands
Figure 3 List of Available Entity Framework Commands

When ready, write the following command line:

> dnx ef dbcontext scaffold "Server=.\sqlexpress;Database=Cars;Trusted_Connection=True;" 
EntityFramework.MicrosoftSqlServer --outputDir Models

The dbcontext command takes an option called scaffold, which generates the proper DbContext and entities from the database specified in the supplied connection string. Of course, you’ll need to replace the server name with yours. EntityFramework.Micro­softSqlServer specifies the data provider that’ll be used for scaffolding. Notice how you can specify an output directory for your data model via the --outputDir option, which is case-sensitive. In this case, the output directory is a folder called Models, which already exists in the project and is the proper, logical place for the DbContext class and entities. After the completion message, you’ll see how the Models folder contains a class file called CarsContext.cs, which contains the CarsContext class that inherits from Db­Context, and a file called Cars.cs, which defines a class called Cars and that exposes the properties that map columns from the Cars table in the database (see Figure 4). Notice that there’s no option to control the pluralization of entity names, so this should be managed manually and is beyond the scope of this article.

Cars Model Class in the Code Editor
Figure 4 Cars Model Class in the Code Editor

At this point you must supply the connection string that the application will use to connect to the database. Instead of placing the connection string into the Web.config file, this can be done in the Startup class. This declares a method called ConfigureServices, which is invoked by the runtime to configure the necessary services via dependency injection (DI), and is the recommended place for supplying the connection string. ConfigureServices takes an argument called services, of type Microsoft.Extensions.Dependency­Injection.IServiceCollection, which stores a list of services that will be injected. Consider these lines of code:

var connection = @"Server=.\sqlexpress;Database=Cars;Trusted_Connection=True;";
services.AddEntityFramework()
  .AddSqlServer()
  .AddDbContext<CarsContext>(options => options.UseSqlServer(connection));

What the second line does is register the necessary Entity Framework and SQL Server services for DI and registers the DbContext class as a service. The AddDbContext method lets you specify the connection string via the DbContextBuilder.UseSqlServer method, invoked through a delegate called options. Both lines must be placed at the very beginning of the ConfigureServices method, whose complete code is shown in Figure 5.

Figure 5 Registering the DbContext Class for Dependency Injection

public void ConfigureServices(IServiceCollection services)
{
  // Add framework services
  var connection = @"Server=.\sqlexpress;Database=Cars;Trusted_Connection=True;";
  services.AddEntityFramework()
    .AddSqlServer()
    .AddDbContext<CarsContext>(options => options.UseSqlServer(
      connection));
  services.AddEntityFramework()
    .AddSqlite()
    .AddDbContext<ApplicationDbContext>(options => options.UseSqlite(
      Configuration["Data:DefaultConnection:ConnectionString"]));
  services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();
  services.AddMvc();
  // Add application services
  services.AddTransient<IEmailSender, AuthMessageSender>();
  services.AddTransient<ISmsSender, AuthMessageSender>();
}

So far, you’ve implemented your data model. Now you need a way to expose actions that the UI will invoke to work against data.

Implementing MVC Controllers

ASP.NET Core supports both Web API services and MVC applications. Web API is the preferred approach if you’re building a RESTful service; the current example is instead a Web application with a UI, so you’ll use MVC. You can implement MVC controllers and views as you would in any ASP.NET MVC application. A controller is a class that inherits from Microsoft.AspNet.Mvc.Controller and exposes actions that the UI (or other clients) can invoke to work against data. To add a controller, in Visual Studio Code right-click the Controllers folder and select New File. When the text box appears, enter CarsController.cs as the new file name. This will add a new C# file that will also open in the code editor. What the new controller needs to implement are methods that let you query, add and delete data. The full listing for the controller is shown in Figure 6 (with comments). Though the code might seem a bit long, IntelliSense will help you write code faster and efficiently.

Figure 6 Implementing an MVC Controller That Works Against Data

using System.Linq;
using Microsoft.AspNet.Mvc;
using CarModels.Models;
namespace CarModels.Controllers
{
  public class CarsController : Controller
  {
    // Declares the DbContext class
    private CarsContext dataContext;
    // The instance of DbContext is passed via dependency injection
    public CarsController(CarsContext context)
    {
      this.dataContext=context;
    }
    // GET: /<controller>/
    // Return the list of cars to the caller view
    public IActionResult Index()
    {
      return View(this.dataContext.Cars.ToList());
    }
    public IActionResult Create()
    {
      return View();
    }
    // Add a new object via a POST request
    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult Create(Cars car)
    {
      // If the data model is in a valid state ...
      if (ModelState.IsValid)
      {
        // ... add the new object to the collection
        dataContext.Cars.Add(car);
        // Save changes and return to the Index method
        dataContext.SaveChanges();
        return RedirectToAction("Index");
      }
      return View(car);
    }
    [ActionName("Delete")]
    public IActionResult Delete(int? id)
    {
      if (id == null)
      {
        return HttpNotFound();
      }
      Cars car = dataContext.Cars.Single(m => m.id == id);
      if (car == null)
      {
        return HttpNotFound();
      }
      return View(car);
    }
    // POST: Cars/Delete/5
    // Delete an object via a POST request
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public IActionResult DeleteConfirmed(int id)
    {
      Cars car = dataContext.Cars.SingleOrDefault(m => m.id == id);
      // Remove the car from the collection and save changes
      dataContext.Cars.Remove(car);
      dataContext.SaveChanges();
      return RedirectToAction("Index");
    }
  }
}

In summary, you have four actions: Index, which returns the list of cars to the caller view; Create, which adds a new car via an HTTP POST request; and Delete and DeleteConfirmed, which wait for user confirmation and remove a car via an HTTP POST request, respectively. With About Index, you could also write a LINQ query to return a filtered list.

Adding and Designing MVC Views

In MVC, views are data-bound Web pages that compose the application’s UI. In this example, you need three views: an Index page that shows the list of cars; a Create page that lets users add new cars; and a Delete page that asks confirmation before deleting a car from the database. Views must be organized into subfolders residing in the Views folder, whose name is used by the application to route Web requests. For instance, if you create a folder called Cars, all the views inside this folder will be opened through the ApplicationName/Cars routing convention. Assuming you’ve created a folder called Cars under Views, right-click it and select New File. Enter Index.cshtml as the file name and press Enter, so that the new file is immediately available in the code editor; based on its extension, Visual Studio Code recognizes it as a Razor file. This view is used to display the full list of items through a table; each row shows the car model, the manufacturer’s name, and a hyperlink that users can click to delete an item. Figure 7 shows the full code for the Index.cshtml page.

Figure 7 Creating an Index View

@model IEnumerable<CarModels.Models.Cars>
@{
  ViewBag.Title = "Cars";
}
<h2>Car models</h2>
<p>
  <a asp-controller="Cars" asp-action="Create">Add New</a>
</p>
<table class="table">
  <tr>
    <th>Car Model</th>
    <th>Brand</th>
  </tr>
  @foreach (var item in Model)
  {
    <tr>
      <td>
        @Html.DisplayFor(modelItem => item.CarModel)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Brand)
      </td>
      <td>
        <a asp-controller="Cars" asp-action="Delete"
          asp-route-id="@item.id">Delete</a>
      </td>
    </tr>
  }
</table>

Notice how the markup leverages the so-called model binding to specify the .NET type for the model class and to invoke and bind its properties for each row. Also, notice how the Delete link points to the same-named action in the Cars controller, supplying the item id via model binding. Similarly, an action called Create points to the Create action in the Cars controller and opens a new view that lets you add new objects. This view is called Create, and you can create one by performing the same steps you did previously with the Index view, which means adding a Create.cshtml file into the Views\Cars subfolder. In this new view, you basically create a data form where users can write information based on the model properties, providing a button that submits information to the bound controller. Figure 8 shows how to accomplish this.

Figure 8 Defining a Create View

@model CarModels.Models.Cars
@{
  ViewBag.Title = "New car";
}
<h2>@ViewData["Title"]</h2>
<form asp-controller="Cars" asp-action="Create" method="post"
  class="form-horizontal" role="form">
  <div class="form-horizontal">
    <div asp-validation-summary="ValidationSummary.All" class="text-danger"></div>
    <div class="form-group">
      <label asp-for="CarModel" class="col-md-2 control-label"></label>
      <div class="col-md-10">
        <input asp-for="CarModel" class="form-control" />
        <span asp-validation-for="CarModel" class="text-danger"></span>
      </div>
      <label asp-for="Brand" class="col-md-2 control-label"></label>
      <div class="col-md-10">
        <input asp-for="Brand" class="form-control" />
        <span asp-validation-for="Brand" class="text-danger"></span>
      </div>
    </div>
    <div class="form-group">
      <div class="col-md-offset-2 col-md-10">
        <input type="submit" value="Create" class="btn btn-default" />
      </div>
    </div>
  </div>
</form>

The last step is adding a new view called Delete.cshtml into the Views\Cars subfolder. When added, type the code shown in Figure 9, which shows detailed information about the item that will be deleted and provides an option to submit or cancel changes.

Figure 9 Creating a Delete View

@model CarModels.Models.Cars
@{
  ViewData["Title"] = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you? The operation cannot be undone.</h3>
<div>
  <h4>Cars</h4>
  <hr />
  <dl class="dl-horizontal">
    <dt>
      @Html.DisplayNameFor(model => model.Brand)
    </dt>
    <dd>
      @Html.DisplayFor(model => model.Brand)
    </dd>
    <dt>
      @Html.DisplayNameFor(model => model.CarModel)
    </dt>
    <dd>
      @Html.DisplayFor(model => model.CarModel)
    </dd>
  </dl>
  <form asp-action="Delete">
    <div class="form-actions no-color">
      <input type="submit" value="Delete" class="btn btn-default" /> |
      <a asp-action="Index">Back to List</a>
    </div>
  </form>
</div>

At this point you have data model, actions and UI. This means you’re ready to start to test the sample application.

Running the Application

You can run an ASP.NET Core application from Visual Studio Code directly. To accomplish this, open the Command Palette, type dnx and press Enter. Next, select dnx: Run Command and press Enter. Then click dnx web. This is the equivalent of typing dnx web in a command prompt. In future releases, you’ll write dotnet run from the command line. At this point, Visual Studio Code starts Kestrel, an open source Web server for ASP.NET Core applications (bit.ly/1rdEfxV), to host your Web app. In Visual Studio Code, you’ll also see a Console window where Kestrel redirects its output and any messages the runtime sends, including the stack trace in case of exceptions, which is particularly useful for debugging purposes. By default, Kestrel starts listening to port 5000, which means that you can open your favorite browser and type http://localhost:5000 to start the application. Figure 10 shows the application running.

The Application Running
Figure 10 The Application Running

In the browser’s Web address bar, type localhost:5000/Cars to open the default view for the Cars controller. As you can see in Figure 11, the application shows the list of cars, as expected.

Application Showing the List of Cars in the Database
Figure 11 Application Showing the List of Cars in the Database

Click Add New, so that you have an option to add a new item (see Figure 12). When you click Create, the new item is saved into the database and the application will navigate back to the previous view, where you’ll see the updated list of cars.

Adding a New Item
Figure 12 Adding a New Item

Now, click the Delete hyperlink near the car you added previously. The Delete view appears, showing the selected item’s details and asking for the user’s confirmation (see Figure 13). Simply click Delete to remove the item and return to the index. Remember that this is a cross-platform Web application, so it can be published to Linux, OS X and Windows.

Deleting an Item
Figure 13 Deleting an Item

Hints About Publishing Your Application

You have alternatives to publishing your ASP.NET Core application, including (but not limited to) Microsoft Azure and IIS. The first option involves enabling Git integration, whereas the second one currently involves the DNX Utility (dnu) and the dnu publish command line and will involve the dotnet publish command line in future releases. Publishing has been discussed on Microsoft resources. Publishing to Azure is discussed at bit.ly/22QXTh6, whereas using dnu is discussed at bit.ly/1TWvfWh.

Wrapping Up

Visual Studio Code lets you write ASP.NET Core applications by leveraging all of the evolved editing features available to C# and to the other file types in the project. Being a cross-platform itself, it’s the perfect companion to start writing MVC applications for Linux, OS X and Windows. The availability of the Entity Framework to different platforms and the opportunity of reusing your existing C# and MVC skills make writing data-centric Web applications an even more amazing experience. Don’t forget to check out the ASP.NET Core and .NET Core documentation for updates about the .NET Core CLI.


Alessandro Del Sole has been a Microsoft MVP since 2008. Awarded MVP of the Year five times, he has authored many books, eBooks, instructional videos and articles about .NET development with Visual Studio. Del Sole works as a solution developer expert for Brain-Sys (www.brain-sys.it), focusing on .NET development, training and consulting. You can follow him on Twitter: @progalex.

Thanks to the following Microsoft technical expert for reviewing this article: James McCaffrey
Dr. James McCaffrey works for Microsoft Research in Redmond, Wash. He has worked on several Microsoft products including Internet Explorer and Bing. Dr. McCaffrey can be reached at jammc@microsoft.com.


Discuss this article in the MSDN Magazine forum