ASP.NET Core

Add Entity Framework Core to an Existing ASP.NET Core Project

I had a Web API application that I was using to test something that had no database interaction at all that I needed to add database interaction too. Going through my posts I didn’t find a guide to add Entity Framework Core to an existing project, so that is what this post is going to cover. We will be using SQLite for our database.

Project Creation

The project we are starting with is just a new ASP.NET Core Web API created using the .NET CLI using the following command from a command prompt.

dotnet new webapi

This gives us a new Web API with no database interaction and makes sure we are all on the same page for the rest of the post.

Project File Changes

Open the csproj file associated with your project. First, we need to add a package reference to the Entity Framework Core tools.

Before:
<ItemGroup>
  <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
</ItemGroup>

After:
<ItemGroup>
  <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
  <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.1" PrivateAssets="All" />
</ItemGroup>

Next, we need to add a reference to the Entity Framework Core Tools for the .NET CLI.

Before:
<ItemGroup>
  <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
</ItemGroup>

After:
<ItemGroup>
  <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
  <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.1" />
</ItemGroup>

The final change to the project file is only needed if you are using SQLite and it is to keep the database file from showing up in the file list. Add the following and adjust app.db to match your database name.

<ItemGroup>
  <None Update="app.db" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

App Settings

Now we need to store the database connection string. Again we are using SQLite in this example so if you are trying to use SQL Server (include LocalDb) your connection string will look much different. This is also a place where you need to replace app.db with the database name you want to use.

Open the appsettings.json file and add a ConnectionStrings section similar to the following.

"ConnectionStrings": {
  "DefaultConnection": "DataSource=app.db"
}

The following is my full settings file after the change just to make sure the context is clear.

{
  "ConnectionStrings": {
    "DefaultConnection": "DataSource=app.db"
  },
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  }
}

Model and Db Context

If you are a long time reader it will be no surprise that the model we will be using is that of a contact. The following is my full contact model.

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 Subregion { get; set; }
    public string PostalCode { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
}

Now that we have a model we need to add a DBContext.

public class ContactsDbContext : DbContext
{
    public DbSet<Contact> Contacts { get; set; }

    public ContactsDbContext(DbContextOptions<ContactsDbContext> options)
        : base(options)
    {

    }
}

Startup

Now that we have the application settings, model, and context from above open up the Startup class and in the ConfigureServices function add the following code to get the ContactsDbContext into the container.

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

Initial Migration

Now that the project is all set to go let’s add an initial migration that will get the table for our contacts set up. From a command prompt in the project directory run the following command.

dotnet ef migrations add Contacts

This will add a Migrations directory to the project with the code needed to add the contacts table. If you want to go ahead and apply the migration to the database run the following command.

dotnet ef database update

Since we didn’t have a database yet the above command creates one which will show up in the root of our project with a name that matches our application settings since we are using SQLite.

Wrapping Up

Adding Entity Framework Core to a project is pretty easy, but not something I do a lot, so this will serve as a good reminder of the steps. Hope it helps you out as well.

Add Entity Framework Core to an Existing ASP.NET Core Project Read More »

Run Multiple Projects in Visual Studio Code

While expanding the sample used in the Electron.NET post to include an API I hit a snag with Visual Studio Code. I have used multiple projects with Visual Studio Code before, but never two distinct applications that I need to run at the same time.  Sample code that contains the two projects, but before any modifications covered in this post can be found here.

Building Multiple Projects

The first issue to tackle was getting both projects to build since they are technically independent. As I’m sure you are aware VS Code doesn’t need a solution file like full Visual Studio does. What I learned during this process was that while a solution file isn’t required once can be used to ensure multiple projects all get built. Using VS Code’s Terminal I ran the following commands to create a new solution and add my two projects to that solution.

dotnet new sln -n ElectronTest
dotnet sln add src/ElectronTest/ElectronTest.csproj
dotnet sln add src/ContactsApi/ContactsApi.csproj

With the solution file in place, I then opened the tasks.json file found in the .vscode directory. In the build task, I removed the path to a specific csproj file and just used the workspace folder.

Before:
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
    "build",
    "${workspaceFolder}/src/ElectronTest/ElectronTest.csproj"
]

After:
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
    "build",
    "${workspaceFolder}"
]

This is just one option on how to handle the builds. I believe another way would be to have two build tasks (one for each project) and use the individual build task in your launch configurations (which we are going to talk about next).

Debugging Multiple Projects

Open up your launch.json file in the .vscode directory. By default you will see a couple of configurations more than likely you will see one named .NET Core Attach and another named .NET Core Launch (web). It is the .NET Core Launch (web) configuration that we are interested in. This configuration controls how our application is launched. If you notice the program property points to the dll created during the build process, in the sample code this is  ${workspaceFolder}/src/ElectronTest/bin/Debug/netcoreapp2.0/ElectronTest.dll. This is all fine but doesn’t give us a way to run both of our projects. Let’s tweak the env property to set the ASPNETCORE_URLS which will control the URL the application is launched with.

Before:
"env": {
    "ASPNETCORE_ENVIRONMENT": "Development"
}

After:
"env": {
    "ASPNETCORE_ENVIRONMENT": "Development",
    "ASPNETCORE_URLS": "http://localhost:5001"
}

Now that the original application’s launch configuration is set we need to add a second launch configuration for our second application. The following is the full configuration section for my second application (the API).

{
    "name": ".NET Core Launch (API)",
    "type": "coreclr",
    "request": "launch",
    "preLaunchTask": "build",
    "program": "${workspaceRoot}/src/ContactsApi/bin/Debug/netcoreapp2.0/ContactsApi.dll",
    "args": [],
    "cwd": "${workspaceRoot}/src/ContactsApi",
    "stopAtEntry": false,
    "launchBrowser": {
        "enabled": false,
        "args": "${auto-detect-url}",
        "windows": {
            "command": "cmd.exe",
            "args": "/C start ${auto-detect-url}"
        },
        "osx": {
            "command": "open"
        },
        "linux": {
            "command": "xdg-open"
        }
    },
    "env": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_URLS": "http://localhost:5000"
    },
    "sourceFileMap": {
        "/Views": "${workspaceRoot}/Views"
    }
}

I started with a copy of the original application and just modified a couple of things. First, the name property is now .NET Core Launch (API) which will help us know which application we are launching later. In the launchBrowser section, I set enabled to false since this is an API and I don’t need to launch the browser when the application starts. The final difference is in ASPNETCORE_URLS to make sure the URLs of the two applications are different. I used http://localhost:5000 in this example.

Now that all our configurations are good to go hop over to the debug section in VS Code.

On the debug you will notice that both of our launch configurations are listed. If you select the API one and hit the green play button it will start the API. With the API running you can then select the web configuration and hit the green play button and you will have both of your applications running in debug mode.

Wrapping Up

While it is not obvious at all how to get multiple applications to run in a single instance of VS Code the process isn’t hard after you do it the first time. I think my Visual Studio experience made figuring this out harder than it should have been. My key to learning how to get this going was on this GitHub issue.

Hopefully, this saved you some of the struggles I went through. Please leave a comment if there are different ways to accomplish this. The code with the final configuration can be found here.

Run Multiple Projects in Visual Studio Code Read More »

Create a Desktop Application using ASP.NET Core and Electron.NET

Electron is a cross-platform (Windows, Linux, and Mac) library for building desktop applications using JavaScript, HTML, and CSS. Even if you have never head of Electron I’m sure you have used some of the desktop applications it has been used to build such as Visual Studio Code, Atom, Slack.

Electron.NET provides a wrapper around Electron with an ASP.NET Core MVC application in the mix. Here is the reason why this was done from the creates of the project.

Well… there are lots of different approaches how to get a X-plat desktop app running. We thought it would be nice for .NET devs to use the ASP.NET Core environment and just embed it inside a pretty robust X-plat enviroment called Electron. Porting Electron to .NET is not a goal of this project, at least we don’t have any clue how to do it. We just combine ASP.NET Core & Electron.

Project Creation

Seems only fitting to use VS Code for this post since it is built using the same base library. From the command line create a new ASP.NET Core MVC application using the following command.

dotnet new mvc

Make note that it is important at this time that you use the MVC template when attempting this and not a Razor Page application. This is more of a warning if you are using Visual Studio to do your project creation and not the CLI command above.

Next, we need to reference the ElectronNET.API NuGet package which can be added using the following command.

dotnet add package ElectronNet.API

Then, open the csproj and add a reference for the Electron.NET CLI tool which should match the following.

<ItemGroup>
     <DotNetCliToolReference Include="ElectronNET.CLI" Version="0.0.9" />
</ItemGroup>

After that make sure and restore packages using the following command.

dotnet restore

Wire-up Election.NET

Open Program.cs and add UseElectron(args) to the WebHost builder chain.

WebHost.CreateDefaultBuilder(args)
    .UseElectron(args)
    .UseStartup<Startup>()
    .Build();

Net, open Startup.cs and add the following line to the bottom of the Configure function. This is what will open the Electron window on startup.

Task.Run(async () => await Electron.WindowManager.CreateWindowAsync());

Finally, run the following from the command prompt to get the project ready to run under Electron. This should only need to be done once.

dotnet electronize init

Run the application

At this point, the application is ready to go. The neat part is you can just hit F5 and it will run like any normal ASP.NET Core application (this would change when you get into Electron specific calls I’m sure) or if you run the following command it will run inside of the Electron shell.

dotnet electronize start

Wrapping up

It was surprisingly simple to get a new application up and running, of course so far the app isn’t anything other than a web site hosted in Electron. My plan is to take this base application and create my normal basic contacts application, which will be the next post. From there I may look into layering in some Electron features.

The completed code can be found here.

Create a Desktop Application using ASP.NET Core and Electron.NET Read More »

Two-factor Authentication in ASP.NET Core 2

This post was going to be an update of the SMS using Twilio Rest API in ASP.NET Core post a made a year or so ago, but once I got the example project created I noticed that the default template has removed SMS as an option for two-factor authentication in favor of authenticator auth support.

This post is going to explore the setup of this new two-factor authentication style. In a follow-up post, I may look at adding back support for SMS as the second factor as that seems like a more common scenario albeit a less secure one.

Project Setup

To create a new Razor Pages application using individual authentication I used the following command from a command prompt. Make sure you are in the directory you want the files to end up. The only reason I mention this is I just spend the last 5 minutes cleaning up my user directory because I forgot to change directories.

dotnet new razor --auth Individual

Next, I move up a directory and used the following command to add a new solution file.

dotnet new sln -n TwoFactorAuth

Finally, I used the following command to add the new project to the solution file. If you aren’t using Visual Studio then you don’t have to have the solution file.

dotnet sln add TwoFactorAuth\TwoFactorAuth.csproj

The project after the above can be found here.

Add a QR Code

Strictly speaking, a QR code isn’t required, but it is much better for users so they don’t have to enter a 32 character key into their authenticator application manually. I followed the official docs to enable QR code generation.

The first step is to download a Javascript QR Code library. I just used the one recommended in the docs, but any would work. This link will take you to a zip download. Open the download and copy qrcode.js and qrcode.min.js into a new qrcode directory inside of your project’s wwwroot/lib/ directory.

Next, find your project’s EnableAuthenticator.cshtml file and update the scripts section at the bottom of the page to the following.

@section Scripts {
    @await Html.PartialAsync("_ValidationScriptsPartial")
    
    <script type="text/javascript" src="~/lib/qrcode/qrcode.js"></script>
    <script type="text/javascript">
        new QRCode(document.getElementById("qrCode"),
            {
                text: "@Html.Raw(Model.AuthenticatorUri)",
                width: 150,
                height: 150
            });
    </script>

Enabling Two-Factor Authentication

The above changes are all that is required, and now we are going to walk through what it looks like for the user. Once logged in click on your user in in the upper right after of the site to open user management.

Next, click the Two-factor authentication link.

Then, click Configure authenticator app link.

This will land you on the page with the QR code.

Now using the authenticator application of your choice you can scan the QR code. Once scanned your authenticator application will display a code. Enter the code in the Verification Code box and click Verify. If all goes well you will be taken to a page that lists a set of recovery code for use if you can’t use your authenticator application for some reason.

Wrapping Up

I think it is awesome how easy the ASP.NET Core team has made the use two-factor authentication. With this being built into the templates it pushes all in the right direction. I do wish they would have left SMS as an option, but hopefully, it wouldn’t be hard to put back in.

The code in the final state can be found here.

Two-factor Authentication in ASP.NET Core 2 Read More »

ASP.NET Core 2 Fails to Publish With Angular 5

I had an issue opened on my Identity Server GitHub repo saying that publishing the client application fails with something like the following error when using server-side rendering.

Can’t resolve ‘./../$$_gendir/ClientApp/app/app.module.browser.ngfactory’

This was only an issue after moving the project to target Angular 5. After some research, it turns out that Angular tools for Webpack has to use a different plugin for ahead of time compiling for Angular 5+. I ended up finding a fix in this issue.

The Fix

In order to resolve the issue, I made the following changes in the webpack.config.js file. The first change is in the require statements at the top of the file.

Before:
const AotPlugin = require('@ngtools/webpack').AotPlugin;

After:
const AngularCompilerPlugin = require('@ngtools/webpack').AngularCompilerPlugin;

Next, make the following replacement in the rest of the file, which should only be two places.

Before:
new AotPlugin

After:
new AngularCompilerPlugin

Wrapping Up

Most of the projects I reference on this blog are written to specifically target the topic I am trying to cover and as such I miss things like testing publish since I’m never going to production with these applications. I really appreciate those of you who find issues and take the time to open an issue on GitHub. Keep them coming, and if you find a solution before I do feel free to submit a pull request.

 

ASP.NET Core 2 Fails to Publish With Angular 5 Read More »

Entity Framework Core with Postgres

With last week’s post, I now have Postgres running in a Docker container. This post is going to cover using Entity Framework Core with Postgres which will happen to be running in the Docker container from last week, but that bit isn’t a requirement for this post. This post is going to be very similar to this one which covered Entity Framework Core with SQLite.

Starting Point

Using Visual Studio 2017 I started with a new ASP.NET Core project using the Web Application template with Individual User Accounts for Authentication. Using Individual User Accounts is an easy way to get all the Entity Framework Core stuff setup.

Add Postgres Nuget Package

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

On the Browse tab search for Npgsql.EntityFrameworkCore.PostgreSQL and then click install.

Configuration Changes

Open the appsettings.json file and change the DefaultConnection in the ConnectionString section to a valid Postgres connection string as in the following example.

Before:
"ConnectionStrings": {
  "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-Postgres-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true"
}

After:
"ConnectionStrings": {
  "DefaultConnection": "Server=localhost;Database=aspnet-Postgres-53bc9b9d-9d6a-45d4-8429-2a2761773502;UserId=yourUserName;Password=yourPassword"
}

Not that a user ID and password are needed. If you are going to be checking your project into source control I recommend in addition to the above you only store the connection string with the real user ID and password in user secrets which don’t get checked into source control. You can find more information on user secrets here.

Startup Changes

The final change needed before running the application is in the ConfigureServices function of the Startup class to switch out SQL Server for Postgres. The following shows an example of the change for the ApplicationDbContext.

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

After:
services.AddDbContext<ApplicationDbContext>(options =>
    options
      .UseNpgsql(Configuration
                 .GetConnectionString("DefaultConnection")));

Run the App

Running the application at this point will work fine until you hit a function that wants to talk to the database. For example, attempting to register a user would result in the following error.

If you see this error don’t panic just follow the instructions and they will get you going. The simplest solution is to just click the blue Apply Migrations button and continue your testing.

Wrapping Up

The application is now ready to go using Postgres. The Entity Framework Core team, as well as the Postgres Entity Framework Core Provider team, have done a great job making everything work with no pain.

The official docs for the provider can be found here. I would love to offer some tooling recommendations for working with Postgres, but I haven’t been working with it enough yet to provide any. If you have any Postgres tools you recommend please leave a comment.

The code in its final state, which has been expanded to include my standard contacts example, can be found here.

Entity Framework Core with Postgres Read More »

Trying the New ASP.NET Core Angular Template with CLI Support

I got hit by the flu that has been going around and now that the fever has passed I thought it would be a good time to try out the new version of the Angular template for ASP.NET Core that works well with the Angular CLI.

Template Installation

Note that at the time of this writing the templates are in the release candidate stage and a new version could be available by the time you are reading this so make sure and check this page for potential updates.

Running the following command from a command prompt will install the RC version of the templates.

dotnet new --install Microsoft.DotNet.Web.Spa.ProjectTemplates::2.0.0-rc1-final

Project Creation

Create a directory for the project and navigate to it in a command prompt. Run the following command to create the new Angular project.

dotnet new angular

Next, if you have a solution you want to add the new project to that can be done with the following command adjusting for the naming of your project and solution.

dotnet sln "ASP.NET Core Basics.sln" add src\AngularWithCli\AngularWithCli.csproj

Installation of Angular CLI

From the command prompt run the following command to install the Angular CLI globally.

npm install -g @angular/cli

After the above, I got the following error trying to run any Angular CLI commands.

You seem to not be depending on “@angular/core”. This is an error.

The problem ended up being that I had not installed all the packages for the project. The issue was cleared up by the following command.

npm install

Angular CLI Usage

Navigate to the ClientApp directory and you can then use all the Angular CLI commands as you would in a stand along Angular application. Some of which can be found here. If you are looking for a quick command to verify all is work the following command works well by running a linter on your project.

ng lint

Wrapping Up

Having templates that are compatible with the Angular and React CLI is a big step forward. The CLIs provide a lot of functionality and by having a setup that doesn’t restrict their usages is a great move. Make note that server-side rendering is no longer enabled by default, but can still be enabled for Angular projects, but not React based projects.

I recommend you check out the official documentation which can be found here.

I hope we see these functionality moves to the other templates that are outside of the templates in this package in order to support Aurelia and Vue.

Trying the New ASP.NET Core Angular Template with CLI Support Read More »

Identity Server: Migration to version 2.1 and Angular HTTP Changes

Version 2.1 of Identity Server 4 was released a few weeks and this post is going to cover updating my sample project to the latest version. The starting point of the code can be found here. We are going to tackle this in sections as there are updates needed for an ASP.NET Core Update, Identity Server Update, and some broken bits in Angular.

ASP.NET Core Update

The sample projects were all on ASP.NET Core version 2.0.0. For each project right-click and select Edit ProjectName.csproj. Make the following change.

Before:
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />

After:
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.3" />

Identity Server Update

Right-click the Identity App project and select Edit IdentityApp.csproj. Next, make the following changes.
Before:
<PackageReference Include="IdentityServer4.EntityFramework" Version="2.0.0" />

After:
<PackageReference Include="IdentityServer4.EntityFramework" Version="2.1.0" />

Next, need to add a couple of Entity Framework migrations to see if there were any data changes with the following commands from a command prompt in the Identity App project directory.

dotnet ef migrations add Configration21 -c ConfigurationDbContext -o Data/Migrations/IdentityServer/Configuration
dotnet ef migrations add PersistedGrant21 -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrant

Turns out that there were no data changes for this version so if you are on version 2.0.0 you can skip this step.

Angular Issues

I’m not sure how I didn’t hit this issue on the last update post, but the Client App needs to be changed to use the new Angular HttpClient. I got the following error when trying to run the client application.

An unhandled exception occurred while processing the request.

NodeInvocationException: No provider for PlatformRef!
Error: No provider for PlatformRef!
at injectionError
After some digging, I tracked the issue down to using HttpModule instead of HttpClientModule. To make this transition we need to make a few changes. In the app.module.shared.ts make the following changes to the imports section.
Before:
import { HttpModule } from '@angular/http';

After:
import { HttpClientModule } from '@angular/common/http';

Next, in the imports array make the following change.

Before:
HttpModule

After:
HttpClientModule

Next, in the webpack.config.vendor.js fille add the following to the vendor array.

'@angular/common/http'

The last changes are to the auth.service.ts and they are extensive so instead of going through them I’m just going to post the full class after all the changes.

import { Injectable, Component, OnInit, OnDestroy, Inject } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Rx';
import { Subscription } from 'rxjs/Subscription';

import { OidcSecurityService, OpenIDImplicitFlowConfiguration } from 'angular-auth-oidc-client';

@Injectable()
export class AuthService implements OnInit, OnDestroy {
    isAuthorizedSubscription: Subscription;
    isAuthorized: boolean;

    constructor(public oidcSecurityService: OidcSecurityService,
        private http: HttpClient,
        @Inject('ORIGIN_URL') originUrl: string,
        @Inject('IDENTITY_URL') identityUrl: string
    ) {
        const openIdImplicitFlowConfiguration = new OpenIDImplicitFlowConfiguration();
        openIdImplicitFlowConfiguration.stsServer = identityUrl;
        openIdImplicitFlowConfiguration.redirect_url = originUrl + 'callback';
        openIdImplicitFlowConfiguration.client_id = 'ng';
        openIdImplicitFlowConfiguration.response_type = 'id_token token';
        openIdImplicitFlowConfiguration.scope = 'openid profile apiApp';
        openIdImplicitFlowConfiguration.post_logout_redirect_uri = originUrl + 'home';
        openIdImplicitFlowConfiguration.forbidden_route = '/forbidden';
        openIdImplicitFlowConfiguration.unauthorized_route = '/unauthorized';
        openIdImplicitFlowConfiguration.auto_userinfo = true;
        openIdImplicitFlowConfiguration.log_console_warning_active = true;
        openIdImplicitFlowConfiguration.log_console_debug_active = false;
        openIdImplicitFlowConfiguration.max_id_token_iat_offset_allowed_in_seconds = 10;

        this.oidcSecurityService.setupModule(openIdImplicitFlowConfiguration);

        if (this.oidcSecurityService.moduleSetup) {
            this.doCallbackLogicIfRequired();
        } else {
            this.oidcSecurityService.onModuleSetup.subscribe(() => {
                this.doCallbackLogicIfRequired();
            });
        }
    }

    ngOnInit() {
        this.isAuthorizedSubscription = this.oidcSecurityService.getIsAuthorized().subscribe(
            (isAuthorized: boolean) => {
                this.isAuthorized = isAuthorized;
            });
    }

    ngOnDestroy(): void {
        this.isAuthorizedSubscription.unsubscribe();
        this.oidcSecurityService.onModuleSetup.unsubscribe();
    }

    getIsAuthorized(): Observable<boolean> {
        return this.oidcSecurityService.getIsAuthorized();
    }

    login() {
        console.log('start login');
        this.oidcSecurityService.authorize();
    }

    refreshSession() {
        console.log('start refreshSession');
        this.oidcSecurityService.authorize();
    }

    logout() {
        console.log('start logoff');
        this.oidcSecurityService.logoff();
    }

    private doCallbackLogicIfRequired() {
        if (typeof location !== "undefined" && window.location.hash) {
            this.oidcSecurityService.authorizedCallback();
        }
    }

    get(url: string): Observable<any> {
        return this.http.get<any>(url, { headers: this.getHeaders() });
    }

    put(url: string, data: any): Observable<any> {
        const body = JSON.stringify(data);
        return this.http.put<any>(url, body, { headers: this.getHeaders() });
    }

    delete(url: string): Observable<any> {
        return this.http.delete<any>(url, { headers: this.getHeaders() });
    }

    post(url: string, data: any): Observable<any> {
        const body = JSON.stringify(data);
        return this.http.post<any>(url, body, { headers: this.getHeaders() });
    }

    private getHeaders() {
        let headers = new HttpHeaders();
        headers = headers.set('Content-Type', 'application/json');
        return this.appendAuthHeader(headers);
    }

    private appendAuthHeader(headers: HttpHeaders) {
        const token = this.oidcSecurityService.getToken();

        if (token === '') return headers;

        const tokenValue = 'Bearer ' + token;
        return headers.set('Authorization', tokenValue);
    }
}

With all those changes made run the following two commands in a command prompt in the Client App project directory.

node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js
node node_modules/webpack/bin/webpack.js

Wrapping up

This post ended up being more about Angular than Identity Server, but it is nice to have everything upgraded to the latest and working.

The files in the completed can be found here.

Identity Server: Migration to version 2.1 and Angular HTTP Changes Read More »

Change ASP.NET Core from npm to Yarn

Over the past couple of months, I have been having some issues with npm. Between the upgrading of npm Windows begin a pain and a version incompatibility with node I have just gotten frustrated with it. This post is going to cover the steps to use Yarn as a replacement for npm in an ASP.NET Core application.

Installation

The first step is to get Yarn installed. Head over to this site and download and run the installer for your operating system.

For Visual Studio, Mads Kristensen created an extension for Yarn that makes the integration much better. The installer for the extension can be downloaded from here.

Conversion

Open a command prompt in the same directory as your project’s package.json file and run the following command.

yarn

This will create a yarn.lock and lay out the node_modules folder using Yarn’s resolution algorithm.

I did hit the following error when I did the yarn command. I left out the specific file that it had an issue with because I am sure yours would be different.

Error: EPERM: operation not permitted, copyfile...

To clear the issue I just deleted the node_modules directory and let Yarn recreate it. It might also work to use a command prompt with administrator privileges.

Visual Studio

With the Yarn extension installed there are a couple of settings that are helpful to change. All the setting we will be changing can be found under the Tools > Options menu. The first is to have yarn install run when the package.json is saved. Look under Web > Yarn Installer for this option.

The second setting is to turn off automatic NPM restore so packages are restored twice. This requires the options under NPM to be set to false. The options can be found in Projects and Solutions > Web Package Management > Package Restore.

The extension helps with Yarn integration, but the integration still isn’t as full-featured as using NPM. At my current level of frustration having to manually restore package when I open a project on a new PC is totally worth it.

Wrapping Up

So far Yarn has been great and I have not hit any issues, but my usage has also been limited. It seems like a solid alternative to NPM.

Make sure and check out Yarn’s official post on migrating from NPM which can be found here. Of specific interest will be the CLI command comparison which can be found here.

Change ASP.NET Core from npm to Yarn Read More »

Auth0: Usage from Angular

This post is a continuation of my exploration of using Auth0 with ASP.NET Core with an API and an Angular front end. I recommend you start with the first post if you are new to Auth0.

This post is going to add a login from Angular in the Client Application as well as accessing the API once logged in. The starting point of the code can be found here.

API Application

To give us an endpoint in the API to call let’s move the SimpleDataController class from the ClientApp/Controllers directory to ApiApp/Controllers directory. Also, remember to adjust the namespace to reflect this move.

To remove some complication we are going to add a CORS policy to the API Application to allow all CORS request. This wouldn’t necessarily something I would recommend for a production application. For more information on CORS check out this post.

To add the CORS policy open the Startup class and add the following to the ConfigureServices function which adds a CORS policy to DI that allows all calls through.

services.AddCors(options =>
{
    options.AddPolicy("default", policy =>
    {
        policy.AllowAnyOrigin()
            .AllowAnyHeader()
            .AllowAnyMethod();
    });
});

Next, in the Configure function, CORS needs to be added to the HTTP pipeline with the policy added above. The following is the full function body for reference, but only the CORS line is new.

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.UseCors("default");
app.UseAuthentication();
app.UseMvc();

Note that the API isn’t currently using Authorization at all and won’t be for this post.

Client Application

Instead of redoing a lot of the same work that I covered in some of my posts on using Identity Server and Angular together I decided to copy the ClientApp directory and use it as a starting point. The rest of the client changes are going to assume the same starting point which means we will be using angular-auth-oidc-client instead of the Auth0 client to do the Open ID Connect bits.

Configuration values from appsettings.json

We need some setting from the ASP.NET Core part of the client application. First, add the following new settings to the appsettings.json file.

"ApiAddress": "http://localhost:50467/api/",
"ClientId": "yourAngularClientId"

Next, Index.cshtml needs to be changed to provide some prerender data. The following shows the new data being passed into the Angular application (this post covers this in detail).

<app asp-prerender-module="ClientApp/dist/main-server"
     asp-prerender-data='new {
    apiUrl = Configuration["ApiAddress"],
    identityUrl = $"https://{Configuration["Auth0:Domain"]}",
    clientId = Configuration["ClientId"]
}'>Loading...</app>

Now that the prerender values are being passed in we need to handle them in the boot.server.ts file in the createServerRenderer export. The following is the full list of values.

export default createServerRenderer(params => {
    const providers = [
        { provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } },
        { provide: APP_BASE_HREF, useValue: params.baseUrl },
        { provide: 'BASE_URL', useValue: params.origin + params.baseUrl },
        { provide: 'ORIGIN_URL', useValue: params.origin + params.baseUrl },
        { provide: 'API_URL', useValue: params.data.apiUrl },
        { provide: 'IDENTITY_URL', useValue: params.data.identityUrl },
        { provide: 'CLIENT_ID', useValue: params.data.clientId },
        { provide: 'URL_CONFIG', useValue: params.data}
    ];

Down a bit in the file, the setImmediate call needs to be changed to the following.

setImmediate(() => {
    resolve({
        html: state.renderToString(),
        globals: {url_Config: params.data}
    });

Next, in the app.module.browser.ts file we need functions for getting the config values as well as the associated providers. The following is the full file without the imports.

@NgModule({
    bootstrap: [AppComponent],
    imports: [
        BrowserModule,
        AppModuleShared
    ],
    providers: [
        { provide: 'ORIGIN_URL', useFactory: getBaseUrl },
        { provide: 'API_URL', useFactory: apiUrlFactory },
        { provide: 'IDENTITY_URL', useFactory: identityUrlFactory },
        { provide: 'CLIENT_ID', useFactory: clientIdFactory },
        AppModuleShared
    ]
})
export class AppModule {
}

export function getBaseUrl() {
    return document.getElementsByTagName('base')[0].href;
}

export function apiUrlFactory() {
    return (window as any).url_Config.apiUrl;
}

export function identityUrlFactory() {
    return (window as any).url_Config.identityUrl;
}

export function clientIdFactory() {
    return (window as any).url_Config.clientId;
}

Finally, in the auth.service.ts file we need to inject the new configuration values. The following is the constructor that takes in the new values as well as uses them in the set up of the OpenIDImplicitFlowConfiguration.

constructor(public oidcSecurityService: OidcSecurityService,
    private http: HttpClient,
    @Inject('ORIGIN_URL') originUrl: string,
    @Inject('IDENTITY_URL') identityUrl: string,
    @Inject('CLIENT_ID') clientId: string
) {
    const openIdImplicitFlowConfiguration = new OpenIDImplicitFlowConfiguration();
    openIdImplicitFlowConfiguration.stsServer = identityUrl;
    openIdImplicitFlowConfiguration.redirect_url = originUrl + 'callback';
    openIdImplicitFlowConfiguration.client_id = clientId;
    openIdImplicitFlowConfiguration.response_type = 'id_token token';
    openIdImplicitFlowConfiguration.scope = 'openid profile apiApp';
    openIdImplicitFlowConfiguration.post_logout_redirect_uri = originUrl + 'home';
    openIdImplicitFlowConfiguration.forbidden_route = '/forbidden';
    openIdImplicitFlowConfiguration.unauthorized_route = '/unauthorized';
    openIdImplicitFlowConfiguration.auto_userinfo = true;
    openIdImplicitFlowConfiguration.log_console_warning_active = true;
    openIdImplicitFlowConfiguration.log_console_debug_active = false;
    openIdImplicitFlowConfiguration.max_id_token_iat_offset_allowed_in_seconds = 10;

    this.oidcSecurityService.setupModule(openIdImplicitFlowConfiguration);

    if (this.oidcSecurityService.moduleSetup) {
        this.doCallbackLogicIfRequired();
    } else {
        this.oidcSecurityService.onModuleSetup.subscribe(() => {
            this.doCallbackLogicIfRequired();
        });
    }
}

Make sure in the Auth0 client setup you allow the callback listed above or you will run into issues.

Wrapping Up

Working on this post further convinced me that Open ID Connect is the way to go. I basically took an implementation that was meant for Identity Server and used it with Auth0.

Make note that the reason the API is unsecured at this point is that I had an issue getting angular-auth-oidc-client to play nicely with Auth0 for some reason. I doubt it is an issue with either product just some sort of missing configuration on my part. This is the part of the post that I sunk so much time on. In the end, I decided to just skip it for now. If anyone does get that setup work I would love to see the sample so I know what I was doing wrong.

The completed code can be found here.

Auth0: Usage from Angular Read More »