ASP.NET Core

Identity Server: Introduction

In the SPA based sample applications, this blog has used so far user authentication has either been completely ignored in order to keep the examples simpler or the sites have used ASP.NET Core’s built in identity to encapsulate the whole SPA. In this post (or series of posts) I am going to share what I learn along the way of creating an Angular (2+) application that utilizes ASP.NET Core as its host/API/backend.

This post isn’t going to cover any code it is just going to be a lot of the information I gathered in the process of learning more about Identity Server.

Following are all the post in this series.

Identity Server: Introduction (this post)
Identity Server: Sample Exploration and Initial Project Setup
Identity Server: Interactive Login using MVC
Identity Server: From Implicit to Hybrid Flow
Identity Server: Using ASP.NET Core Identity
Identity Server: Using Entity Framework Core for Configuration Data
Identity Server: Usage from Angular

Identity Server

According to their docs IdentityServer4 is an OpenID Connect and OAuth 2.0 framework for ASP.NET Core which enables Authentication as a Service, Single Sign-on, API Access Control and a Federation Gateway.

Obviously, that covers a lot of scenarios. The two that I am interested in are Authentication as a Service and the API Access Control which has driven my research which means that the other aspects of IdentityServer4 will not be included.

Official Samples

The IdentityServer GitHub account has a samples repo that contains a ton of examples. I have found the quickstart area of the repo to be the most helpful when starting out.

Based on all the quickstarts samples it looks like a typical setup involves a minimum of three projects. One for the API, one for the client and one for Identity Server. As you go through the samples the number of projects increase, but that is because of a wider range of scenarios that the sample is trying to cover.

References for learning

Damienbod has a whole series of blog posts related to IdentityServer4 and code to go along with it which can be found here. As a side note if you are interested in ASP.NET Core and you aren’t following damienbo you should be he has a ton of great content.

Blog posts
Videos

Identity Server Alternatives

Identity Server isn’t the only way to go there is a number of Software as a Service options that cover a lot of same scenarios. The following are some examples.

Auth0 – Check out the .NET Core related blogs by Jerrie Pelser
Stormpath
Amazon Cognito

Wrapping up

Obviously, I didn’t get a lot covered on how to actually do something with IdentityServer, but I wanted to share my starting point. This is an area I am going to continue digging it to and sharing information about as I learn more.

If you have any resources in this area please leave a comment below.

Identity Server: Introduction Read More »

Upgrading a JavaScript Services Application

As part of the ASP.NET Core Basics series of posts, JavaScript Services was used to create a couple of front end for a basic contacts API using Aurelia and Angular 2. Theses applications were created a few months ago and JavaScript Services has kept moving since then. This post is going to look at one strategy for taking an application created on an older version of JavaScript Services and update it to match the current version. This post will be following the upgrade of the Angular project from ASP.NET Core Basics repo with the starting point of the code being from this release.

The strategy

One of the considerations when doing this upgrade was getting the changes that happen on the ASP.NET Core side of the application and not just the JavaScript bits. In order to make sure that nothing was missed I decided to use JavaScript Services to generate a new application and use that to compare with the implementations in the existing application.

Create comparison application

This is going to assume JavaScript Services is already installed. If it isn’t this page has instructions or this post has sections that deal with creating a new application using JavaScript Services.

The update

Following is the files that changed during this update. This is also the list of files I would check anytime an upgrade needs to be done.

Angular.csproj
ClientApp/boot-client.ts
ClientApp/boot-server.ts
Program.cs
package.json
webpack.config.js
webpack.config.vendor.js

There were a fair amount of changes in the files listed above and instead of posting the code the differences can be found here. The previous diff didn’t contain the webpack.config files and those diffs can be found here and here.

After all the files have been updated make sure to run the following command from a command prompt in your project directory to make sure webpack has vendor related items regenerated.

webpack --config webpack.config.vendor.js

Wrapping up

This post is a lighter on the details that I do most of the time, but this type of upgrade would just have been a wall of code and not been overly useful and the commits on GitHub are a much better guide to what the upgrade looked like. My feeling is that over time the number of changes going forward may end up being smaller and easier to integrate.

Both the Aurelia and Angular projects have been upgraded and the final version of the code can be found here.

Upgrading a JavaScript Services Application Read More »

Entity Framework Core with SQLite Migration Limitations

This is part of what has turned into a series on Entity Framework Core with SQLite. The other parts can be found below.

Entity Framework Core with SQLite
Entity Framework Core Errors Using Add-Migration
Entity Framework Core with SQLite Scaffolding

The starting point of the code for this post can be found here.

Migration Limitations when using SQLite

SQLite’s ALTER TABLE is limited which in turn limits what Entity Framework Core can do via a migration. The official docs on the subject can be found here. These limitations are on the Entity Framework Team’s list of issues as an open enhancement and can be tracked here.

As long as you are just adding new tables or columns you would never notice the limitation, but if you have spelling problems like I do then the need to rename a column can be important. Thankfully things like ReSpeller (link is to the pro page, but a free version is available in ReSharpers extension manager) help with my spelling issues.

Unsupported example with a column rename

As an example of how to handle a migration that isn’t supported, we are going to rename the State property of the Contact class to Subregion.

Rename property on the model

Open the Contact class which can be found in the Models directory and make the following change.

Before:
public string State { get; set; }

After:
public string Subregion { get; set; }
Add a migration

With the property name change using the following command in the Package Manager Console to create a new migration.

Add-Migration RenameContactStateToSubregion -c ContactsDbContext

Which produces the following migration class.

public partial class RenameContactStateToSubregion : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.RenameColumn(
            name: "State",
            table: "Contacts",
            newName: "Subregion");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.RenameColumn(
            name: "Subregion",
            table: "Contacts",
            newName: "State");
    }
}
Error trying to apply the migration

As expected when an attempt to apply the above migration results in the following exception.

System.NotSupportedException: SQLite does not support this migration operation (‘RenameColumnOperation’). For more information, see http://go.microsoft.com/fwlink/?LinkId=723262.

Modify migration to manually rename the column

Searching for how to rename a column in SQLite will turn up a lot of results including this from the official docs and answers like this on StackOverflow. The gist of the how to do a rename is to create a new table with the desired schema, copy the data from the original table, drop the old table, and finally rename the new table to match the original name.

Now knowing the process the migration above can be modified to apply SQL directly instead of using Entity Framework Core to generate the SQL. This can be done by using the Sql function of the MigrationBuilder class. The following is the resulting migration.

public partial class RenameContactStateToSubregion : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql(
            @"PRAGMA foreign_keys = 0;

              CREATE TABLE Contacts_temp AS SELECT *
                                            FROM Contacts;
              
              DROP TABLE Contacts;
              
              CREATE TABLE Contacts (
                  Id         INTEGER NOT NULL
                                     CONSTRAINT PK_Contacts PRIMARY KEY AUTOINCREMENT,
                  Address    TEXT,
                  City       TEXT,
                  Email      TEXT,
                  Name       TEXT,
                  Phone      TEXT,
                  PostalCode TEXT,
                  Subregion  TEXT
              );
              
              INSERT INTO Contacts 
              (
                  Id,
                  Address,
                  City,
                  Email,
                  Name,
                  Phone,
                  PostalCode,
                  Subregion
              )
              SELECT Id,
                     Address,
                     City,
                     Email,
                     Name,
                     Phone,
                     PostalCode,
                     State
              FROM Contacts_temp;
              
              DROP TABLE Contacts_temp;
              
              PRAGMA foreign_keys = 1;");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
    }
}

You will notice that I didn’t bother doing the Down function, but the same idea would apply when trying to undo a migration. SQLiteStudio or similar tools can be used to generate the SQL above if SQL isn’t something you want to deal with.

Fix other references to the renamed field

This isn’t really the topic of this post, but I wanted to throw in a reminder that after a rename like this there are places that will need to be updated that the tooling may not have picked up. For example, make sure all your views are using the new column as well as any bind statements in your controllers.

Wrapping up

The first time I hit the need to rename a column and it resulted in an exception it was extremely frustrating. Over time as I learned what the tooling around SQLite provides it has become less of an issue. I look forward to seeing what the Entity Framework team does in the future around this issue. The finished code can be found here.

Entity Framework Core with SQLite Migration Limitations Read More »

Entity Framework Core with SQLite Scaffolding

This is the third in what is turning into a series of post about using SQLite with Entity Framework Core. This post is going to cover adding a migration, scaffolding a controller and related views, and a few things that are harder to do using SQLite. The following are the first two post.

Entity Framework Core with SQLite
Entity Framework Core Errors Using Add-Migration

Adding Model, DbContext, Controller, and Views

If you have any experience with Entity Framework Core or have read any of my past entries on the subject this section is going to repeat some of the same information, but I am including it so someone who is looking for a full example will have it.

Model

In the Models folder add a Contact class similar the following.

public class Contact
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string PostalCode { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
}
DbContext

In the Data folder add a ContactsDbContext that inherits from DbContext. The following is an example that auto applies migrations to a database, if you don’t need that functionality it can be dropped out.

public sealed class ContactsDbContext : DbContext
{
    private static bool _created;

    public DbSet<Contact> Contacts { get; set; }

    public ContactsDbContext(DbContextOptions<ContactsDbContext> options)
        : base(options)
    {
        if (_created) return;
        Database.Migrate();
        _created = true;
    }
}

Now that the application has a model and a related DbContext the following can be used to add a migration that will create a Contacts in the SQLite database. Run from the Package Manager console.

Add-Migration AddContacts -Context ContactsDbContext

Add-Migration is a Powershell command to add a migration (surprise!), AddContacts is the name of the migration and -Context ContactsDbContext is an argument that lets the command know which DbConext to use. The Context is only needed if your application has more than one DbContext.

Controller and Views

With the above complete Visual Studio provides some tooling that makes it very fast to create a controller with views for listing, adding, editing, and deleting items. To begin right-click on the Controllers folder and select Add > New Scaffolded Item.

Select the MVC Controller with views, using Entity Framework option and click Add.

On the next dialog use the drop downs to select a model class and a data context class. Then verify the controller name and click add.

When the process completes the following items will have been added to your project.

Controllers
 - ContactsController.cs
Views
 - Contacts
   - Create.cshtml
   - Delete.cshtml
   - Details.cshtml
   - Edit.cshtml
   - Index.cshtml
Add to nav bar

To add a link to the new section of the app to the nav bar open the _Layout.cshtml in the Views/Shared/ directory. The following is the section of the file that needs to be changed to add an item to the nav bar.

<ul class="nav navbar-nav">
    <li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
    <li><a asp-area="" asp-controller="Contacts" asp-action="Index">Contacts</a></li>
    <li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
    <li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
</ul>

Specifically, the following line was added to provide access to the contact list page.

<li><a asp-area="" asp-controller="Contacts" asp-action="Index">Contacts</a></li>

Wrapping up

With the above, the application will be runnable. The code for this post can be found here. The next post in this series will cover the limitations of migrations when using SQLite with Entity Framework Core.

 

Entity Framework Core with SQLite Scaffolding Read More »

Entity Framework Core Errors Using Add-Migration

I started off trying to expand my sample from last week’s post and hit some issues when trying to add a migration for a new DbContext.

The Setup

I added the following DbContext that only has one DbSet and auto applies migrations in the constructor.

using EfSqlite.Models;
using Microsoft.EntityFrameworkCore;

public sealed class ContactsDbContext : DbContext
{
    private static bool _created;

    public DbSet<Contact> Contacts { get; set; }

    public ContactsDbContext(DbContextOptions<ContactsDbContext> options)
        : base(options)
    {
        if (_created) return;
        Database.Migrate();
        _created = true;
    }
}

The command

Using Visual Studio’s Package Manager Console I ran the following command.

Add-Migration AddContacts -Context ContactsDbContext
Error 1 – No parameterless constructor

The above command resulted in the following error.

No parameterless constructor was found on ‘ContactsDbContext’. Either add a parameterless constructor to ‘ContactsDbContext’ or add an implementation of ‘IDbContextFactory<ContactsDbContext>’ in the same assembly as ‘ContactsDbContext’.

I read the first sentence and added a parameterless constructor to ContactsDbContext. I did think it was strange that a parameterless constructor wasn’t required the other contexts I had written in the past, but the error said to add a parameterless constructor so that is what I did.

Error 2 – System.InvalidOperationException: No database provider has been configured for this DbContext

Now having a parameterless constructor I ran the Add-Migration command again and was greeted with the following error.

System.InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.

The second error forced me to step back and think more about what the problem was as it didn’t have an action I could take as the first sentence, which is, of course, my fault for not fully digesting what the error was saying.

The fix

The bit I was missing was the fact that I hadn’t added the following to the ConfigureServices function of the project’s Startup class.

services.AddDbContext<ContactsDbContext>(options =>
    options.UseSqlite(Configuration.GetConnectionString("Sqlite")));

With the above added I removed the parameterless constructor from ContactsDbContext and was able to successfully run the add migration command again.

Wrapping up

The moral of the story is to actually read the full error message before running off and trying to fix the problem. The second error message saying “using AddDbContext on the application service provider” is what triggered me to head in the right direction.

This was also a good reminder that tools like the ones used by Add-Migration can/do compile the project they are being used on in order to have enough context to perform their tasks.

Entity Framework Core Errors Using Add-Migration Read More »

Entity Framework Core with SQLite

All the applications used as examples for ASP.NET Core and Entity Framework Core from this site so far used database running SQL Server/SQL Express. In addition to the Microsoft-based SQL databases, Entity Framework Core has support for a number of other database providers. This post is going to look at using SQLite. A full list of the support database providers can be found here.

Starting point

Using Visual Studio 2017 I started with a new ASP.NET Core project using Individual User Accounts which ensured all the Entity Framework Core bits were present. The template in RC 4 used packages based on the Core 1.0.3 which I upgraded to 1.1.0. The project at this point can be found here.

Just a side note this project was created when Visual Studio 2017 was at the RC 4 stage. This code associated with this post will be updated when Visual Studio 2017 is released.

Naming warning

As you will be able to see with the structure of the solution I started this work using the project name SQLite. With this project name, it was impossible to get the SQLite package to install. If you see something like the following renaming your project should get you running.

Cycle detected: 
   Sqlite (>= 1.0.0) -> Microsoft.EntityFrameworkCore.Sqlite (>= 1.1.0) -> Microsoft.Data.Sqlite (>= 1.1.0) -> SQLite (>= 3.13.0)

This issue is where I found out what the problem was.

Add SQLite Packages

Right-click on the project file and click Manage NuGet Packages.

Select Browse and in the search box enter “Microsoft.EntityFramework.Sqlite” and install the two packages that are found.

Remove SqlServer Packages

While still in the Manage NuGet Packages screen click on the Installed tab. Select and uninstall the following packages.

Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.SqlServer.Design

Configuration changes

Open appsettings.json and in the ConnectionStrings delete the line for DefaultConnection. Next, in the same section add a line for a SQLite connection string. The following is the result.

"ConnectionStrings": {
  "Sqlite": "Data Source=Database.db"
}

The above will expect the database file to be in the same location as the application is running. For a debug build the database file can be found in the \bin\Debug\netcoreapp1.0\ directory of the project.

Startup changes

The final location to change is in the ConfigureServices function of the Startup class. The following shows the addition of the application DB context before and after the changes.

Before:
services
  .AddDbContext<ApplicationDbContext>(options =>  options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
 
After:
services
  .AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(Configuration.GetConnectionString("Sqlite")));

Wrapping up

The application is now runnable using SQLite as its backing data store. At this point, the only thing using data access is related to identity. The first time an attempt is made to access the database you may be prompted to apply migrations.

I have been using SQLite Studio to view the data in my database if you have that need outside of the application it does a good job.

The code in its final state can be found here.

Entity Framework Core with SQLite Read More »

ASP.NET Core Conversion to csproj with Visual Studio 2017 and update to 1.1.1

On March 7th Visual Studio 2017 was released bring the ASP.NET Core tools preview. ASP.NET Core 1.1.1 was also released. This post is going to cover converting the project from my MailGun post from being project.json based to csproj as well as migrating from the project from ASP.NET Core 1.0.2 to 1.1.1. Here is the project as it stood before I made any changes.

Visual Studio 2017

The first step is to get a version of Visual Studio 2017 (VS 2017) installed. The download page can be found here. Make sure to grab the community edition if you are looking for a free fully-featured IDE option. Check out this blog post from Microsoft on the many new features Visual Studio 2017 brings.

The installer for VS 2017 has changed a lot from previous versions. The way it works now is you select the workload you use and it only installs the bit it has to to keep the size of install down. The following is a screen shot from my install. I have a lot more workloads checked that is needed for just an ASP.NET Core application. At a minimum make sure the “ASP.NET and web development” workload gets installed. If you are interested in cross-platform development scroll to the bottom and also check “.NET Core cross-platform development”.

Project conversion

When you open the solution in VS 2017 it will prompt you to do a one-way upgrade.

After the conversion is complete a migration report will open. Below is mine. I had no issues, but if there were any this report should give you some idea of how they should be addressed.

As part of the conversion process, the following file changes happened.

Deleted:
global.json
ASP.NET-Core-Email.xproj
project.json

Added:
ASP.NET-Core-Email.csproj

That is all there is to the conversion. The tooling takes care of it all and your project should keep work just as before. The sample project post conversion can be found here.

Migration from 1.0.x to 1.1.1

The migration is almost as simple as the project conversion. In the solution explorer right click on the project to be migrated and select Properties.

Find the Target framework selection and select .NETCoreApp 1.1. Then save your solution.

Next, open the NuGet Package Manager. It can be by right click on the project and selecting Manage NuGet Packages or from the Tools > NuGet Package Manager > Manage NuGet Packages for Solution.

Select the Updates tab and update all the related packages to 1.1.1 and click the Update button.

If you want a specific list of all the package changes check out the associated commit.

The only other change needed is in the constructor of the Startup class.

Before:
builder.AddUserSecrets();

After:
builder.AddUserSecrets<Startup>();

Wrapping up

After all the changes above your solution will be on the latest released bits. Having been following releases since beta 4 I can tell you this is one of the easiest migration so far. I may be partial, but .NET and Microsoft seem to be getting better and better over the last couple of years.

I am going to leave you with a few related links.

ASP.NET Core 1.1.1 Release Notes
Announcing New ASP.NET Core and Web Dev Feature in VS 2017
Project File Tools – Extension for IntelliSense in csproj
Razor Language Services – Extension for tag helper Intellisense

ASP.NET Core Conversion to csproj with Visual Studio 2017 and update to 1.1.1 Read More »

Log Requests and Responses in ASP.NET Core

Note: An updated version of this post for ASP.NET Core 3 and above is available.

As part of trying to do some debugging, I needed a way to log the requests and responses. Writing a piece of middleware seemed to be a good way to handle this problem. It also turned out to be more complicated that I had expected to deal with the request and response bodies.

Middleware

In ASP.NET Core middleware are the components that make up the pipeline that handles request and responses for the application. Each piece of middleware called has the option to do some processing on the request before calling next piece of middleware in line. After execution returns from the call to the next middleware, there is an opportunity to do processing on the response.

The pipeline for an application is set in the Configure function of the Startup class. Run, Map and Use are the three types of middleware. Run should only be used to terminate the pipeline. Map is used for pipeline branching. Use seems to be the most common type of middleware that does some processing and call the next middleware in line. For more detail see the official docs.

Creating Middleware

Middleware can be implemented as a lambda directly in the Configure function, but more typically it is implemented as a class that is added to the pipeline using an extension method on IApplicationBuilder. This example will be going the class route.

This example is a piece of middleware that using ASP.NET Cores built-in logging to log requests and responses. Create a class called RequestResponseLoggingMiddleware.

The class will need a constructor that takes to arguments both will be provided by ASP.NET Core’s dependency injection system. The first is a RequestDelegate for the next piece of middleware to be called. The second is an ILoggerFactory which will be used to create a logger. The RequestDelegate is stored to the class level _next variable and the loggerFactory is used to create a logger which is stored to the class level _logger variable.

public class RequestResponseLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    public RequestResponseLoggingMiddleware(RequestDelegate next,
                                            ILoggerFactory loggerFactory)
    {
        _next = next;
        _logger = loggerFactory
                  .CreateLogger<RequestResponseLoggingMiddleware>();
    }
}

Add an Invoke function which is the function that will be called when your middleware is run by the pipeline. The following is the function that does nothing other than call the next middleware in the pipeline.

public async Task Invoke(HttpContext context)
{
     //code dealing with request

     await _next(context);

     //code dealing with response
}

Next, add a static class to simplify adding the middleware to the application’s pipeline. This is the same pattern the built-in middleware uses.

public static class RequestResponseLoggingMiddlewareExtensions
{
    public static IApplicationBuilder UseRequestResponseLogging(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestResponseLoggingMiddleware>();
    }
}

Adding to the pipeline

To add the new middleware to the pipeline open the Startup to the Configure function and add the following line.

app.UseRequestResponseLogging();

Keep in mind that the order in which middleware is added can make a difference in how the application behaves. Since the middleware this post is dealing with is logging I have placed it near the begging of the pipeline just before app.UseStaticFiles().

Logging requests and responses

Now that the setup work for our new middleware is done we will come back to its Invoke function. As I stated above this ended up being more complicated that I expected, but thankfully I found this by Sul Aga which really helped me work through the issues I was having.

I created a couple of helper functions that we will look at first. The following is the function call to create the string that will be logged for a request.

private async Task<string> FormatRequest(HttpRequest request)
{
    var body = request.Body;
    request.EnableRewind();

    var buffer = new byte[Convert.ToInt32(request.ContentLength)];
    await request.Body.ReadAsync(buffer, 0, buffer.Length);
    var bodyAsText = Encoding.UTF8.GetString(buffer);
    request.Body = body;

    return $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {bodyAsText}";
}

The key to getting this function to work and allow reading of the request body was request.EnableRewind() which allows us to read from the beginning of the stream. The rest of the function is pretty straight forward.

The next function is used to get the string to that will be used to log the response body. This function looks simpler than it is and only works because of how it is called from the Invoke function.

private async Task<string> FormatResponse(HttpResponse response)
{
    response.Body.Seek(0, SeekOrigin.Begin);
    var text = await new StreamReader(response.Body).ReadToEndAsync(); 
    response.Body.Seek(0, SeekOrigin.Begin);

    return $"Response {text}";
}

Finally, the Invoke which does the logging and jumps through some hoops to allow the response body to be read.

public async Task Invoke(HttpContext context)
{
    _logger.LogInformation(await FormatRequest(context.Request));

    var originalBodyStream = context.Response.Body;

    using (var responseBody = new MemoryStream())
    {
        context.Response.Body = responseBody;

        await _next(context);

        _logger.LogInformation(await FormatResponse(context.Response));
        await responseBody.CopyToAsync(originalBodyStream);
    }
}

As you can see the trick to reading the response body is replacing the stream being used with a new MemoryStream and then copying the data back to the original body steam. This works and is a concept I found in Sul’s blog post. I don’t know how much the affect performance and would make sure to study how it scales or just avoid using it in production as much as possible.

Wrapping up

This entry didn’t turn out anything like I expected. I came into this looking to do a very simple post due to some time restrictions and it turned into something larger. I hope you find it helpful. I didn’t do a full repo for this week’s post, but you can a gist with the middleware classes here.

Log Requests and Responses in ASP.NET Core Read More »

Email with ASP.NET Core Using Mailgun

Sending emails from ASP.NET Core using Mailgun is a topic I covered in this post almost a year ago. The previous post was before ASP.NET Core hit 1.0 and I didn’t save or upload the code to GitHub. Based on the comments on the post I decided to redo the post using the current version of ASP.NET.

Starting point

For this post, I created a new ASP.NET Core Web Application targeting .NET Core using Individual User Accounts for authentication. The project before any changes for email can be found here.

UI and Controller change to support email

The project template comes with all the UI and controller functions need to support email, but they are commented out. The following is going to walk through uncommenting the proper code.

Account controller

Starting with the Register function the code to send a confirmation email needs to be uncommented and the existing call to _signInManager.SignInAsync should be commented out to keep a user from being signed in before their email address has been confirmed. The following is after the changes.

var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Action("ConfirmEmail", "Account", 
                             new { userId = user.Id, code = code }, 
                             protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
   $"Please confirm your account by clicking this link: 
     <a href='{callbackUrl}'>link</a>");
//await _signInManager.SignInAsync(user, isPersistent: false);

Next, in the Login function add a check to verify a user’s account has been confirmed before allowing them to sign in. The new code starts with var user = await _userManager.FindByNameAsync(model.Email); the code above it is just to provide context.

 public async Task<IActionResult> Login(LoginViewModel model, 
                                        string returnUrl = null)
 {
      ViewData["ReturnUrl"] = returnUrl;
      if (ModelState.IsValid)
      {
          var user = await _userManager.FindByNameAsync(model.Email);
          if (user != null)
          {
              if (!await _userManager.IsEmailConfirmedAsync(user))
              {
                  ModelState.AddModelError(string.Empty, 
                              "You must have a confirmed email to log in.");
                  return View(model);
              }
          }

Finally, in the ForgotPassword function uncomment the following to enable sending the user a password reset link.

var code = await _userManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = Url.Action("ResetPassword", "Account", 
                             new { userId = user.Id, code = code }, 
                             protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Reset Password",
   $"Please reset your password by clicking here: <a          
     href='{callbackUrl}'>link</a>");
return View("ForgotPasswordConfirmation");
Forgot password view

To enabled the UI related to sending an email for a forgotten password open ForgotPassword.cshtml found in the Views/Account/ directory and uncomment the following.

<form asp-controller="Account" asp-action="ForgotPassword" 
      method="post" class="form-horizontal">
    <h4>Enter your email.</h4>
    <hr />
    <div asp-validation-summary="All" class="text-danger"></div>
    <div class="form-group">
        <label asp-for="Email" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input asp-for="Email" class="form-control" />
            <span asp-validation-for="Email" class="text-danger"></span>
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
             <button type="submit" 
                     class="btn btn-default">Submit</button>
        </div>
    </div>
</form>

Warning for sites with existing users

The changes above will cause issues for any existing users since they will not have completed the email confirmation step keeping them from being able to log in or reset passwords. Manually marking existing users as confirmed can be done by updating the EmailConfirmed bit field to true in the AspNetUsers table.

Mailgun

Mailgun is an email service run by Rackspace that provides a simple API for sending emails. The free level of the service allows up to 10k emails to be sent a month.

You can sign up for an account here. Once logged in go to the Domains section.

Next, select your domain should only be one if you are on a new account. This will take you to a screen that looks like the following some of which will be needed to connect with the Mailgun API. I took the time to replace my information with a fake version so this screen shot could be referenced using the values from the screenshot for the rest of the post.

Configuration

Settings class

In order to hold and load Mailgun email related settings add a new EmailSettings class. In the sample project, this class can be found in the Configuration directory. The following is the full contents of the file.

public class EmailSettings
{
    public string ApiKey { get; set; }
    public string ApiBaseUri { get; set; }
    public string RequestUri { get; set; }
    public string From { get; set; }
}
User secrets introduction

User secrets is a concept in ASP.NET Core used to set configuration items and have them stored outside of the project so they will be excluded from version control. They are a great way to store private API key and related items which is why they will be used to store our Mailgun configuration items. I will be coving the basics here, but for a more detail explanation check out the official docs on the topic of app secrets.

Setting user secrets

In the Solution Explorer right-click on the project and select Manage User Secrets.

This will open the secrets.json file which will be used to store secrets related to the select project. Keep in mind this file is stored in your user directory in an unencrypted way so don’t view it as a secured store.

Based on the screenshot above from Mailgun’s domain detail page the json file would look like the following. The RequestUri is the only setting not pulled from the domain settings above and would just need fakesandbox replaced with the sandbox ID for your domain.

{
  "EmailSettings": {
    "ApiKey": "api:key-fakeapikey",
    "ApiBaseUri": "https://api.mailgun.net/v3/",
    "RequestUri": "fakesandbox.mailgun.org/messages",
    "From": "[email protected]"
  }
}
Loading user secrets in Startup

In the ConfigureServices function of the Startup class the EmailSettings section of our user secrets can be loaded and made available via the dependency injection system using the following line of code.

services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));

Not that user secrets are only meant to be used for development and for a production build of the applications the settings would need to be moved to a different location such as environment variables or Azure Key Vault.

Using Mailgun to send email

Not that the application has the email sending portion of the UI enabled the SendEmailAsync function of the AuthMessageSender class needs to be implemented. The class can be found in the MessageServices.cs file of the Services directory.

Injection of email settings

The first change needed is to add a class level variable to store email settings and to add a constructor that will allow the email setting to be injected.

private readonly EmailSettings _emailSettings;

public AuthMessageSender(IOptions<EmailSettings> emailOptions)
{
    _emailSettings = emailOptions.Value;
}
Sending an email

The body of the SendEmailAsync function is where the call to Mailgun’s API will be made using the email setting injected via the class’s constructor. The following is the full body of the function.

using (var client = new HttpClient { BaseAddress = 
                                     new Uri(_emailSettings.ApiBaseUri) })
{
    client.DefaultRequestHeaders.Authorization = 
      new AuthenticationHeaderValue("Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes(_emailSettings.ApiKey)));

    var content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("from", _emailSettings.From),
        new KeyValuePair<string, string>("to", email),
        new KeyValuePair<string, string>("subject", subject),
        new KeyValuePair<string, string>("html", message)
    });

    await client.PostAsync(_emailSettings.RequestUri, 
                           content).ConfigureAwait(false);
}

The Mailgun API key is sent as an authentication header value with the rest of the parameters being sent via form URL encoded content. Finally, the Request URI from the email settings is used to send the post request to Mailgun.

If you just need to send a plain text instead of HTML the “html” key can be replaced with “text”.

Authorized recipients required for test domain

When using Mailgun with the default test domain note that only emails addressed to Authorized Recipients will be delivered. To add a recipient click Authorized Recipients button on Mailgun’s Domains page.

This will take you to the Authorized Recipients page where you can use the Invite New Recipient button to add a recipient.

Enter the email address you want to add and click the Send Invite button. After the email address is confirmed mail to that address will be delivered. Keep in mind this is only for test accounts and doesn’t have to be done when being used with a real domain.

Using logs to verify state of emails

During my testing, I wasn’t seeing emails come through and I thought something was wrong with my code, but it turned out that Mailgun was getting the request to send the mail they just hadn’t be processed yet. The Logs section of your Mailgun account is helpful for determining if they are getting your request to send an email or not.

As you can see in the screenshot the email request was accepted, but not yet delivered. It was 10 minutes later before the email was actually delivered. I am not sure if this delay is just for test domains or if would apply to live ones as well.

Other Email Options

Mailgun is obviously not the only option for sending emails. This post from Mashape lists 12 API providers. In addition SMTP is also an option which this post by Steve Gordon covers.

Wrapping up

The code finished code that goes with this post can be found here. Thank you to all the commenters on the original post for stepping in when I didn’t have all the answer or code available.

Email with ASP.NET Core Using Mailgun Read More »

Angular 2 – Router links, click handlers, routing parameters

As with last week’s post this post is going to cover multiple topics related to while creating a contact detail page to go along with the existing contact list page that is part of the ASP.NET Basics repo, but this time using Angular 2 instead of Aurelia. The code before any changes can be found here. If you are using the sample application keep in mind all the changes in this post take place in the Angular project.

Creating a detail view and view model

Create contactdetail.component.html in ClientApp\app\components\contacts. This view that will be used to display all the details of a specific contact. It will also link back to the contact list. The following image shows the folder structure after the view and view model have been added.

View

The following is the full contents of the view.

<h1>Contact Details</h1>
<hr />
<div *ngIf="contact">
    <dl class="dl-horizontal">
        <dt>ID</dt>
        <dd>{{contact.id}}</dd>
        <dt>Name</dt>
        <dd>{{contact.name}}</dd>
        <dt>Address</dt>
        <dd>{{contact.getAddress()}}</dd>
        <dt>Phone</dt>
        <dd>{{contact.phone}}</dd>
        <dt>Email</dt>
        <dd>{{contact.email}}</dd>
    </dl>
</div>
<a routerLink="/contact-list">Back to List</a>
<hr />

*ngIf is adding/removing the associated div based on a contact being set or not.

{{value}} is Angular’s one-way binding syntax. For more details check out the docs.

<a routerLink=”/contact-list”> is using Angular to generate a link back to the contact list component.

View model

For the view model add contactdetail.component.ts in the ClientApp\app\components\contacts folder which is the same folder used for the view.

Make not of the imports needed to make this view model work. To start off Contact is needed to define what the definition of a contact is and ContactService is being used to load the data for a specific contact.

Angular’s core is imported to allow the view model to set as a component using @Component decorator as well as to all implementation of OnInit lifecycle hook.  Angular’s router is being used in the ngOnInit function to allow access the parameters of the route that caused the route to be triggered using this.route.params.

The switchMap operator from reactive extensions is used to map the id from the route parameters to a new observable that has the result of this.contactService.getById.

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import 'rxjs/add/operator/switchMap';
import { Contact } from './contact';
import { ContactService } from './contact.service';

@Component({
    selector: 'contactdetail',
    template: require('./contactdetail.component.html'),
    providers: [ContactService]
})
export class ContactDetailComponent implements OnInit {
    contact: Contact;

    constructor(private route: ActivatedRoute,
                private router: Router,
                private contactService: ContactService) { }

    ngOnInit(): void {
        this.route.params
            .switchMap((params: Params) => 
                   this.contactService.getById(params['id']))
            .subscribe((contact :Contact) => this.contact = contact);
    }
}

Adding get by ID to the Contact Service

The existing ContactService doesn’t provide a function to get a contact by a specific ID so one needs to be added.

The following calls the API in the Contacts project and uses the result to create an instance of a  Contact as a promise which is returned to the caller.

getById(id: string): Promise<Contact> {
    return this.http.get(this.baseUrl + id)
        .toPromise()
        .then(response => response.json())
        .then(contact => new Contact(contact))
        .catch(error => console.log(error));
}

The base URL was also moved to a class level variable so that it could be shared.

Add a route with a parameter

To add the new contact detail to the list of routes that the application handles open app.module.ts in the ClientApp/app folder. First, add an import at the top of the file for the new component.

import { ContactDetailComponent } from './components/contacts/contactdetail.component';

Next, add the ContactDetailComponent to the declarations array of the @NgModule decorator.

declarations: [
    AppComponent,
    NavMenuComponent,
    CounterComponent,
    FetchDataComponent,
    ContactListComponent,
    ContactDetailComponent,
    HomeComponent
]

Finally, add the new route to the RouteModule in the imports section of the @NgModule decorator.

RouterModule.forRoot([
    { path: '', redirectTo: 'home', pathMatch: 'full' },
    { path: 'home', component: HomeComponent },
    { path: 'counter', component: CounterComponent },
    { path: 'fetch-data', component: FetchDataComponent },
    { path: 'contact-list', component: ContactListComponent },
    { path: 'contact-detail/:id', component: ContactDetailComponent },
    { path: '**', redirectTo: 'home' }
])

path is the pattern used to match URLs. In addition, parameters can be used in the form of :parameterName. The above route will handle requests for http://baseurl/contact-detail/{id} where {id} is an ID of a contact. As demonstrated above in the ngOnInit function of the view model route.params can be used to access route parameters.

component is used to locate the view/view model that goes with the route.

Integrating the detail view with the contact list

The contact list view and view model needed the following changes to support the contact detail page.

View model

A variable was added for the ID of the select contact was as well as a onSelect function which takes a contact and gets called when a contact is selected. The following is the fully contact list view model.

import { Component, OnInit } from '@angular/core';
import { Contact } from './contact';
import { ContactService } from './contact.service';

@Component({
    selector: 'contactlist',
    template: require('./contactlist.component.html'),
    providers: [ContactService]
})
export class ContactListComponent implements OnInit {
    contacts: Contact[];
    selectedContactId: number = null;

    constructor(private contactService: ContactService) { }

    ngOnInit(): void {
        this.contactService.getAll()
            .then(contacts => this.contacts = contacts);
    }

    onSelect(contact) {
        this.selectedContactId = contact.id;
    }
}

The changes to the view model were not required to add the contact detail page, but are used show how to set up a click handler the view side. In the future, the selected contact will come in handy when the list and details were shown at the same time.

View

The amount of data being displayed was reduced to just ID and name. A column was added with a link to the details page. The following is the full view.

<h1>Contact List</h1>

<p *ngIf="!contacts"><em>Loading...</em></p>

<table class="table" *ngIf="contacts">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let contact of contacts">
            <td>{{contact.id}}</td>
            <td>{{contact.name}}</td>
            <td><a [routerLink]="['/contact-detail', contact.id]" (click)="onSelect(contact)">Details</a></td>
        </tr>
    </tbody>
</table>

(click)=”onSelect(contact)” will cause the onSelect function of the view model to be called with the related contact when the associated element is clicked.

[routerLink]=”[‘/contact-detail’, contact.id]” use the router to create a line to the contact details page passing the contact ID as a parameter.

As a reminder of how to use a route’s parameter here is the ngOnInit function from the contact detail view model.

ngOnInit(): void {
    this.route.params
        .switchMap((params: Params) => this.contactService.getById(params['id']))
        .subscribe((contact :Contact) => this.contact = contact);
}
 Wrapping up

As with the related Aurelia post, there are a lot of topics covered in this post, but they are all related to the process of adding a new page and route to the application.

The code including all the changes for this post can be found here.

 

Angular 2 – Router links, click handlers, routing parameters Read More »