ASP.NET Core

ASP.NET Core Basics: React with an API

In the past, I have done some exploration on Aurelia and Angular via the ASP.NET Core Basics series. This post is going to take a similar approach as I start doing some exploration with React. The code for the project will be in the same repo as the previous basics examples and will be utilizing the same API to pull data. The code before adding the React project can be found here.

This post is going to cover adding a React project to the existing using the React template that is now built into Visual Studio. The same thing can be accomplished using the .NET CLI so don’t feel like Visual Studio is required. The goal for the React project in this initial post will be to connect to the contacts API and download a list of contacts and render that to the screen. In future posts, I hope to expand this functionality to match that of the Aurelia and Angular projects.

Project Creation

Right-click and select Add > New Project.

In the Add New Project dialog select the ASP.NET Core Web Application. In the case of the sample, the project will be named React. Click OK to continue.

On the next screen make sure and select ASP.NET Core 2.0 and the React.js template. Then click OK.

The following is the resulting React project in the context of the full solution.

Next, make sure and run npm install from a command prompt in the React project’s directory to ensure all the npm packages get restored.

Adding the Contact List

Inside the ClientApp/components/ directory add a file name ContactList.tsx. TSX is the TypeScript version of the React JSX file type. The official docs on JSX can be found here. Since this is my first time working with React I took the FetchData.tsx file and copied the contents and used that as the starting point for my contact list. To lead with there is an interface for what should define a contact.

interface Contact {
    id: number;
    name: string;
    address: string;
    city: string;
    state: string;
    postalCode: string;
    phone: string;
    email: string;
}

Next, we have an interface for the state of this component with contains a loading flag and an array of contacts.

interface ContactListState {
    contacts: Contact[];
    loading: boolean;
}

In the constructor for the component is where the data is pulled from the API using fetch. The data from the API is then saved to the state of the component using the setState function.

constructor() {
    super();
    this.state = { contacts: [], loading: true };

    fetch('http://localhost:13322/api/contactsApi/')
        .then(response => response.json() as Promise<Contact[]>)
        .then(data => {
            this.setState({ contacts: data, loading: false });
        });
}

Next, the component has a function named renderContactsTable which takes an array of contacts and returns how they should be rendered. In this case, the contacts are rendered to a table that displays the contact ID and Name.

private static renderContactsTable(contacts: Contact[]) {
    return <table className='table'>
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
            </tr>
        </thead>
        <tbody>
            {contacts.map(contact =>
                <tr key={contact.id}>
                    <td>{contact.id}</td>
                    <td>{contact.name}</td>
                </tr>
            )}
        </tbody>
    </table>;
}

Finally, there is the render function. As you can guess this is what gets called to render the component. In this case, either “Loading” or the contact list gets displayed depending on if the contact list data has been loaded or not.

public render() {
    let contents = this.state.loading
        ? <p><em>Loading...</em></p>
        : ContactList.renderContactsTable(this.state.contacts);

    return <div>
        <h1>Contact List</h1>
        {contents}
    </div>;
}

The following is the full file for reference.

import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import 'isomorphic-fetch';

interface ContactListState {
    contacts: Contact[];
    loading: boolean;
}

export class ContactList extends React.Component<RouteComponentProps<{}>, ContactListState> {
    constructor() {
        super();
        this.state = { contacts: [], loading: true };

        fetch('http://localhost:13322/api/contactsApi/')
            .then(response => response.json() as Promise<Contact[]>)
            .then(data => {
                this.setState({ contacts: data, loading: false });
            });
    }

    public render() {
        let contents = this.state.loading
            ? <p><em>Loading...</em></p>
            : ContactList.renderContactsTable(this.state.contacts);

        return <div>
            <h1>Contact List</h1>
            {contents}
        </div>;
    }

    private static renderContactsTable(contacts: Contact[]) {
        return <table className='table'>
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Name</th>
                </tr>
            </thead>
            <tbody>
                {contacts.map(contact =>
                    <tr key={contact.id}>
                        <td>{contact.id}</td>
                        <td>{contact.name}</td>
                    </tr>
                )}
            </tbody>
        </table>;
    }
}

interface Contact {
    id: number;
    name: string;
    address: string;
    city: string;
    state: string;
    postalCode: string;
    phone: string;
    email: string;
}

Add Contact List to Navigation

Now that we have the contact list component it needs to be added to the navigation menu. The first step is to add it to the application’s router. This can be found in the routes.tsx file. The file is short so I am going to include the full content. Lines 7 and 13 are the ones added to handle our contact list.

import * as React from 'react';
import { Route } from 'react-router-dom';
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import { FetchData } from './components/FetchData';
import { Counter } from './components/Counter';
import { ContactList } from './components/ContactList';

export const routes = <Layout>
    <Route exact path='/' component={Home} />
    <Route path='/counter' component={Counter} />
    <Route path='/fetchdata' component={FetchData} />
    <Route path='/contactlist' component={ContactList} />
</Layout>;

The last change is to add a navigation link to the NavMenu found in the NavMenu.tsx file. As I am sure most of us are used to adding an item to the nav menu is just adding a new li, but with the React specific NavLink bit.

<li>
  <NavLink to={'/contactlist'} activeClassName='active'>
      <span className='glyphicon glyphicon-th-list-alt'></span> Contact List
  </NavLink>
</li>

Wrapping Up

React is different than both Aurelia and Angular. Don’t take that as a good or bad thing. I don’t plan to pick on a side on the Angular vs React debate I just want to get a good feel for the different frameworks. So far the React experience has been pretty nice and I look forward to doing more exploration.

You can find the finished code for this post here.

ASP.NET Core Basics: React with an API Read More »

Identity Server: Migration to ASP.NET Core 2

The Identity App that is part of my IdentityServer sample project is the last application I have on GitHub (of the ones that will get upgraded) that needs an upgrade to ASP.NET Core. The starting point of the project before any changes can be found here. This post assumes that you have already followed my generic ASP.NET Core 2 migration post, which can be found here, on the project you are migrating. One final note of caution this post has been written using the RC1 version of the Identity Server NuGet packages and then moved to the final version so there will be two different related pull requests that will have to be looked at to get the full picture of all the changes.

Package Changes

The first change is to get a version of the Identity Server packages what will work from ASP.NET Core 2.

Before:
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="1.0.1" />
<PackageReference Include="IdentityServer4.EntityFramework" Version="1.0.1" />

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

Database Initialization

I wasted a lot of time on finding out this was an issue when I was trying to create Entity Framework migrations and kept getting Unable to create an object of type ‘ApplicationDbContext’. Add an implementation of ‘IDesignTimeDbContextFactory‘ errors. The gist is database initialization needs to be moved out of Startup and context constructors.

Let’s start with the ApplicationDbContext and remove the following code from the constructor as well as the associated property.

if (_migrated) return;
Database.Migrate();
_migrated = true;

Next, in the Configure function of the Startup class remove the following line.

IdentityServerDatabaseInitialization.InitializeDatabase(app);

We still need the database initialization code to run, but where should that be done? In the Main function of the Program class seems to be the new recommended location. The following is the new Main function.

public static void Main(string[] args)
{
    var host = BuildWebHost(args);

    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;

        try
        {
            IdentityServerDatabaseInitialization.InitializeDatabase(services);
        }
        catch (Exception ex)
        {
            var logger = services.GetRequiredService<ILogger<Program>>();
            logger.LogError(ex, "An error occurred Initializing the DB.");
        }
    }

    host.Run();
}

InitializeDatabase now needs to take an IServiceProvider instead of an IApplicationBuilder. This forced a lot of lines to change so the following is the full class.

public static class IdentityServerDatabaseInitialization
{
    public static void InitializeDatabase(IServiceProvider services)
    {
        PerformMigrations(services);
        SeedData(services);

    }

    private static void PerformMigrations(IServiceProvider services)
    {
        services
          .GetRequiredService<ApplicationDbContext>()
          .Database.Migrate();
        services
          .GetRequiredService<ConfigurationDbContext>()
          .Database.Migrate();
        services
          .GetRequiredService<PersistedGrantDbContext>()
          .Database.Migrate();
    }

    private static void SeedData(IServiceProvider services)
    {
        var context = services.GetRequiredService<ConfigurationDbContext>();

        if (!context.Clients.Any())
        {
            foreach (var client in Config.GetClients())
            {
                context.Clients.Add(client.ToEntity());
            }
            context.SaveChanges();
        }

        if (!context.IdentityResources.Any())
        {
            foreach (var resource in Config.GetIdentityResources())
            {
                context.IdentityResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }

        if (!context.ApiResources.Any())
        {
            foreach (var resource in Config.GetApiResources())
            {
                context.ApiResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }
    }
}

Startup Changes

Most of the changes to the Startup class are in the ConfigureServices function, but some cross with the Configure function as well. The existing AddIdentityServer extension has multiple changes especially if you are using Entity Framework for your configuration data. AddTemporarySigningCredential is now AddDeveloperSigningCredential. The following is the new version including configuration data.

services.AddIdentityServer()
    .AddDeveloperSigningCredential()
    .AddAspNetIdentity<ApplicationUser>()
    .AddConfigurationStore(options =>
    {
      options.ConfigureDbContext = builder =>                 
        builder.UseSqlite(Configuration
                          .GetConnectionString("DefaultConnection"),
                          db => db.MigrationsAssembly(migrationsAssembly));
    })
    .AddOperationalStore(options =>
    {
      options.ConfigureDbContext = builder =>
        builder.UseSqlite(Configuration
                          .GetConnectionString("DefaultConnection"),
                          db => db.MigrationsAssembly(migrationsAssembly));
    });

The way to handle registration of external authentication has changed as well. For example, this application uses Twitter. The UseTwitterAuthentication call in the Configure function needs to be removed. The following added to the bottom of the ConfigureServices is now the proper way to add external authentication providers.

services.AddAuthentication().AddTwitter(twitterOptions =>
{
    twitterOptions.ConsumerKey = 
         Configuration["Authentication:Twitter:ConsumerKey"];
    twitterOptions.ConsumerSecret = 
         Configuration["Authentication:Twitter:ConsumerSecret"];
});

Entity Framework

The new changes in Identity from the ASP.NET Core team included a new foreign key which is one of the things that Sqlite migrations can’t actually do. Since I don’t really have any data I care about I just deleted the database and the existing migrations and snapshots and regenerated everything. If you are using Sqlite and this isn’t an option for you check out this post for some options. If you aren’t using Sqlite then the migrations should work fine. The following are the commands to generate migrations for the 3 contexts that the Identity Application uses.

dotnet ef migrations add InitConfigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/Configuration

dotnet ef migrations add InitPersistedGrant -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrant

dotnet ef migrations add InitApplication -c ApplicationDbContext -o Data/Migrations

Quick Start UI Changes

As part of going from the RC1 version to the Final version, the Identity Server team updated the UI and related bits to be in line with the new features added in the ASP.NET Core 2.0 release. Turns out that resulted in a lot of changes. Since I haven’t done any custom work in this area of my Identity Application I deleted the related files in my local project and pulled from the ASP.NET and Entity Framework Combined sample. I am going to give a good idea of all the files I replace, but in case I miss something GitHub will have the full story.

In the Controllers folder replace AccountController.cs and ManageController.cs. Add or replace the following folders:  Extensions, Models, Quickstart, Services, and Views.

Application Insights Error

I ran into the following error.

System.InvalidOperationException: No service for type ‘Microsoft.ApplicationInsights.AspNetCore.JavaScriptSnippet’ has been registered.

You may or may not see it, but if you do open the _Layout.cshtml and remove the following two lines.

@inject Microsoft.ApplicationInsights.AspNetCore.JavaScriptSnippet JavaScriptSnippet


@Html.Raw(JavaScriptSnippet.FullScript)

Wrapping up

If you hit any issues not covered above make sure and check out the breaking changes issue. The completed code can be found here for part 1 and here for part 2.

Identity Server: Migration to ASP.NET Core 2 Read More »

Identity Server: Deploy to Azure

This post is going to cover taking the existing set of applications we have been using to learn about Identity Server and deploying them to Azure. The starting point of the code can be found here.

Prep Work

The applications as they stand from the link above are not ready to be pushed to Azure most due to some configuration changes that are needed. We will go through each of the applications and take the hard-coded values and move them to appsettings.json.

API Application Configuration

The API application needs two configuration values for the address of the Identity Application and the address of the Client Application. The following two lines need to be added to the application’s appsettings.json file.

"IdentityServerAddress": "http://localhost:5000",
"ClientAddress": "http://localhost:5002"

Then in the Startup class, the values need to be used. The Identity Server address is used in the JWT Bearer setup.

Before:
o.Authority = "http://localhost:5000";

After:
o.Authority = Configuration["IdentityServerAddress"];

Then the Client address is used in the CORS setup.

Before:
policy.WithOrigins("http://localhost:5002")

After:
policy.WithOrigins(Configuration["ClientAddress"])
Identity Application Configuration

The Identity application needs a configuration value for the address of the address of the Client Application. The following line needs to be added to the application’s appsettings.json file.

"ClientAddress": "http://localhost:5002"

Next, the Config class needs a reference to configuration passed into the GetClients function.

public static IEnumerable<Client> GetClients(IConfiguration configuration)

Next, the references to http://localhost:5002 need to be replaced with the value from the configuration. The following is one example.

Before:
RedirectUris = { "http://localhost:5002/signin-oidc" },

After:
RedirectUris = { $"{configuration["ClientAddress"]}/signin-oidc" },
Identity Application Entity Framework

As part of publishing this set of applications, this example is going to use Azure SQL and right now the application is set up to use SQLite. In the Startup class replace UseSqlite with UseSqlServer. The following is an example of one of the needed replacements.

Before:
options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));

After:
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

When switching database providers make sure to delete and recreate your database migrations. I didn’t to begin with and it cost me a lot of time in changing down a strange error which this post covers.

Client Application Configuration

The Client application needs two configuration values for the address of the Identity Application and the address of the API Application. The following two lines need to be added to the application’s appsettings.json file.

"IdentityServerAddress": "http://localhost:5000",
"ApiAddress": "http://localhost:5001/"

Then in the Startup class, the Identity Server Address needs to be used in the AddOpenIdConnect call.

Before:
options.Authority = "http://localhost:5000";

After:
options.Authority = Configuration["IdentityServerAddress"];

Next, the configuration values need to be passed to the Angular application. This process ended up being harder to figure out that I had anticipated and turned into a full blog post on its own. See this post for the details. The code for all the changes will also be on GitHub in case you need to the the diff for the client application.

Publish to Azure

Right-click on the Identity Application and select Publish.

This will show the Publish screen which provides the option to publish to Azure. We don’t have an existing App Service so we are going to create a new one. This page in the official docs explains all the options available on the publish screen. Click the publish button to continue.

The next screen that shows is the Create App Service Screen. I used all the default values and created a new Resource Group and App Service Plan. Keep in mind that the resource group and plan will be reused for the remaining two applications we are looking deploy. The only thing that will change between the applications on this screen will be the App Name.

The services tab looks like the following.

Next in the additional resources box lets hit the plus button next to SQL Database since our group of applications is going to need somewhere to store data. This will take us to the Configure SQL Database screen.

Since I don’t already have a SQL Server setup I am going to hit the New button to add one. That results in the next screen where you enter a name for the server as well as a username and password. After entering the required information click OK.

This will put you back on the configure database screen with most of it filled out. Make sure to set the database name you want to use.

Finally back on the Create App Service screen, you will see all the resources that you selected and configured. When you are satisfied with what you see click the Create button and let Azure do its magic.

When it is done you will see the profile now listed on the Publish page.

The above needs to be repeated for both the API and Client Applications, but using the Resource Group and App Service plan created above. Each profile should use a unique application name.

Identity Application Azure Configuration

The Identity Application needs access to the database that we created above. This means we need to set the DefaultConnection. The first step is to determine what the connection string should be. On the Azure Portal in your list of resources select the SQL database that we created above.

On the next page copy the provided connection string. Now navigate to the Identity App Service and under the Settings section select Application settings. Scroll down and find the Connection strings section and enter the copied value as the DefaultConnection.

Just above the Connection strings section we also need to enter a few values in the App settings section. For the Identity Application, we need the Twitter key and secret as well as the address of the client application. The following is a screenshot minus the actual values.

For the ClientAddress use the URL found in the Overview of the Client App’s App Service page.

API Application Azure Configuration

From the list of resources select the API App’s App Service page and in the Settings section select Application settings. In the App settings section add values for IdentityServerAddress and ClientAddress. As with the ClientAddress above the URLs for each application can be found on their respective App Service pages.

Client Application Azure Configuration

From the list of resources select the Client App’s App Service page and in the Settings section select Application settings. In the App settings section add values for IdentityServerAddress and ApiAddress.

Wrapping Up

At this point, you should be able to load up the application at the client address provided by Azure and have a working application. Overall the deployment to Azure was pretty easy. Getting the applications prepared to be deployed was a bit more challenging and sent me down a couple of rabbit holes. The code in its final state can be found here.

Identity Server: Deploy to Azure Read More »

Pass ASP.NET Core Appsettings Values to Angular

As part of getting my set of Identity Server 4 sample applications to run in Azure, I needed a way in the Client Application to pass some configuration values from appsettings.json to the Angular front end that could be used both during server-side rendering and client-side rendering. This application is using JavaScriptServices. This solution may need tweaking if your application isn’t using JavaScriptServices. The code for the client application can be found here.

Settings

In this example, we need to pass the address of our Identity Server and API from appsettings.json to Angular. The following is the settings file for this example.

{
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  },
  "IdentityServerAddress": "http://localhost:5000",
  "ApiAddress": "http://localhost:5001/"
}

Providing Configuration Data to Angular

In this application, Angular is loaded from the index action of the home controller. This view can be found in the Views/Home folder in the Index.cshtml file. The following is the file before any changes.

@{
    ViewData["Title"] = "Home Page";
}

<app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>

<script src="~/dist/vendor.js" asp-append-version="true"></script>
@section scripts {
    <script src="~/dist/main-client.js" asp-append-version="true"></script>
}

The first change needed is to inject the configuration data using ASP.NET Core’s DI system. Add the following two lines at the top of the file.

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Now the configuration data from the application is available to this view. Next, we need to pull a couple of values out of the configuration data and pass it to the Angular application. To do this we are going to use the asp-prerender-data tag helper. You can read more about it in the official docs. The idea is you construct an object which is then serialized and stored in params.data. In our example, we are passing the URLs for the Identity and API Applications.

<app asp-prerender-module="ClientApp/dist/main-server"
     asp-prerender-data='new {
    apiUrl = Configuration["ApiAddress"],
    identityUrl = Configuration["IdentityServerAddress"]
}'>Loading...</app>

The above is creating a new object with an apiUrl property and an identityUrl property. The following is the full completed view for reference.

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration
@{
    ViewData["Title"] = "Home Page";
}

<app asp-prerender-module="ClientApp/dist/main-server"
     asp-prerender-data='new {
    apiUrl = Configuration["ApiAddress"],
    identityUrl = Configuration["IdentityServerAddress"]
}'>Loading...</app>

<script src="~/dist/vendor.js" asp-append-version="true"></script>
@section scripts {
    <script src="~/dist/main-client.js" asp-append-version="true"></script>
}

Angular Server-Side Boot

When Angular gets prerendered on the server-side it runs the code in the boot.server.ts file. This is where we will set up the providers needed on for the server side prerender. This is the bit that I missed for the longest time when trying to get this example going. I kept trying to find a way to add the providers in the app.module.server.ts file. Add any providers you need to the providers constant. For example, the following is passing URLs for an API and Identity Server in addition to the defaults provided by JavaScriptServices.

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: 'API_URL', useValue: params.data.apiUrl },
    { provide: 'IDENTITY_URL', useValue: params.data.identityUrl }
];

Lower in the same file we can pass through the configuration values to the client side render as globals on the window object. To do this add a globals property to the object being passed to the resolve call.

return new Promise<RenderResult>((resolve, reject) => {
    zone.onError.subscribe((errorInfo: any) => reject(errorInfo));
    appRef.isStable.first(isStable => isStable).subscribe(() => {
        // Because 'onStable' fires before 'onError', we have to delay slightly before
        // completing the request in case there's an error to report
        setImmediate(() => {
            resolve({
                html: state.renderToString(),
                globals: {url_Config: params.data}
            });
            moduleRef.destroy();
        });
    });
});

The above will have the URLs as part of a single object, but you could have each URL as its own property if you prefer.

Angular Client-Side

Now that the server-side has providers for API URL and Identity URL we need to provide the client-side with the same capabilities. These changes will be in the app.module.browser.ts file. The first step is to add providers for each.

providers: [
    { provide: 'ORIGIN_URL', useFactory: getBaseUrl },
    { provide: 'API_URL', useFactory: apiUrlFactory },
    { provide: 'IDENTITY_URL', useFactory: identityUrlFactory },
    AppModuleShared
]

Next, we need functions to return the URLs from the url_Config property of the window object which the following two functions do.

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

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

Wrapping Up

With the above, you can now use your configuration values from ASP.NET Core and pass them through to your Angular application. In hindsight, the process is pretty simple, but getting to that point took me much longer to figure out than I would like to admit. I hope this post saves you some time!

Pass ASP.NET Core Appsettings Values to Angular Read More »

Swagger and Swashbuckle: Disable Try It Out

In last week’s post, I walked through adding Swagger support to an ASP.NET Core 2 API using the Swashbuckle. One of the awesome things about Swashbuckle is it provides an integration with swagger-ui.

Try it out!

One of the features of the UI integration is the ability to invoke an end point using the “Try it out!” button. This feature is awesome during development but may not be something you want to allow, depending on the use case, for a production end point.

Disable Try it out!

I tried googling lots of different things to find the option to disable the “Try it out” button and had a really hard time finding an answer. It didn’t help that I want the button text to be “Try it now” for some reason. Thankfully it truly was a failure on my part and there is a provided way to disable “Try it out” and it is much more flex able than what I was initially looking for.

In the Configure function of the Startup class find the call to app.UseSwaggerUI. Adding c.SupportedSubmitMethods(new string[] {}); will completely disable “Try it out”. The following is the full call to app.UseSwaggerUI just to provide context.

app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "Contacts API V1");
    c.SupportedSubmitMethods(new string[] {});
});

The great thing about the way this is set up if you can allow some actions and not others. For example, say you wanted to allow get actions but disable the rest. The following would allow for that.

c.SupportedSubmitMethods(new [] {"get"});

One word of caution the above is case sensitive and if you use Get instead of get “Try it out” will remain disabled.

Swagger and Swashbuckle: Disable Try It Out Read More »

Swagger and Swashbuckle with ASP.NET Core 2

This post is going to be very similar to a post from last December which can be found here. A lot has changed since then and this post is going to add Swagger to an existing ASP.NET Core application using Swashbuckle much like the one from last year. The starting point of the code can be found here.

What is Swagger?

Swagger is a specification used to document an API. As I am sure we all know API documentation tends to get out of date fast and a lot of times is a low priority.  Swagger aims to help solve that problem using a format that is both human and machine readable which can be maintained in either JSON or YAML. The documentation can be auto generated using a tool like Swashbuckle which provides away to keep your consumers up to date. Check out this post by the Swagger team for the full introduction.

What is Swashbuckle?

Swashbuckle provides auto generation of Swagger 2.0, a UI, etc. The project takes all the pain out of getting going with Swagger as well as providing tools and hooks for using and customizing Swagger related items. The full description can be found here.

Adding Swashbuckle

Using your favorite method of NuGet interaction, add the Swashbuckle.AspNetCore NuGet package to your project. Personally, I have gotten where I edit the csproj file to add new packages. If that is your style you would need to add the following package reference.

<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />

This one package provides all the functionality we will need.

Wiring up Swashbuckle

Now that the Swashbuckle package is installed, there are a few changes that are needed in the Startup class to get everything wired up. First, in the ConfigureServices function, the Swagger generator needs to be added to DI.

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new Info { Title = "Contacts API", Version = "v1"});
});

AddSwaggerGen allows for configuration of options, but here we are just setting a name and a minimal amount of information.

In the Configure function Swagger needs to be added to the request pipeline in order to expose the Swagger generated data. I placed this after UseMvc.

app.UseSwagger();

At this point, the Swagger generated JSON would be available at {yourBaseUrl}/swagger/v1/swagger.json. To take a step further let’s expose the UI that comes with Swashbuckle. Add the following just below app.UseSwagger().

app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "Contacts API V1");
});

Now a UI based on your API is available at {yourBaseUrl}/swagger with zero extra work on your part. The following is the UI for the post contact route in the example project.

As you can see the UI provides a great view of your API as well as ways to try it out and the potential responses that should be expected from a call.

Controller Considerations

All of this wonderful functionality doesn’t come for free of course. In order for Swashbuckle to pick up your routes, your controller will need to use attribute based routing instead of depending on convention based routing.

In order for Swashbuckle to know the return types and of your controller actions may need to have some attributes added. This won’t be required if your action return a specific type, but if you are returning an IActionResult you should attribute your action with all the ProducesResponseType you need to cover the results of your action. For example, the following is the action definition for the Post in the screen shot above.

[HttpPost]
[ProducesResponseType(typeof(Contact), 200)]
[ProducesResponseType(typeof(IDictionary<string, string>), 400)]
[ProducesResponseType(typeof(void), 400)]
[ProducesResponseType(typeof(void), 404)]
[ProducesResponseType(typeof(void), 409)]
public async Task<IActionResult> PostContact([FromBody] Contact contact)

Wrapping up

Swashbuckle makes it easy to add Swagger to a project. I feel that it also provides a huge value for anyone trying to consume an API. It is of course not a magic bullet and communication with your API consumers about API changes will still be critical.

Microsoft’s docs have a great walk through which can be found here. It does more in-depth on customizing your setup and as far as modifying the look of the UI. I also recommend checking out the GitHub page for the project which can be found here.

The finished code can be found here.

Swagger and Swashbuckle with ASP.NET Core 2 Read More »

Identity Server: API Migration to ASP.NET Core 2

After writing the basic migration guide from ASP.NET Core 1.1.x to 2.0 I embarked on the task of upgrading the rest of the projects I have on GitHub. For the most part, it has been a pretty smooth transition. This post is going cover the differences that I hit while converting an API that is part of my IdentityServer sample project. This assumes that you have already followed my other migration post which can be found here.

Package Changes

The source of this conversion being different is that the IdentityServer4.AccessTokenValidation NuGet package is not currently supported on ASP.NET Core 2. Token validation can be done using bits provided by the framework. This is the recommended path suggested by the IdentityServer team as posted on this issue. Longer term you may want to switch back if you have a need for more features not provided by the Microsoft implementation as pointed out in this issue.

As for the actual change, just remove the reference to IdentityServer4.AccessTokenValidation from your project using the NuGet UI, Package Manager Console, or by editing the csproj file.

Startup

All the rest of the changes are in the Startup class. First, in the Configure function app.UseIdentityServerAuthentication gets replaced with app.UseAuthentication.

Before:
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
    Authority = "http://localhost:5000",
    RequireHttpsMetadata = false,
    ApiName = "apiApp"
});

After:
app.UseAuthentication();

In the ConfigureServices function is now where JWT Bearer options are set up. First, we have to add the type of authentication the API is going to use and then the options for JWT Bearer are set, which will match the settings that were being used before with the IdentityServer package.

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = 
                               JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = 
                               JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
    o.Authority = "http://localhost:5000";
    o.Audience = "apiApp";
    o.RequireHttpsMetadata = false;
});

Wrapping up

With the above, your API can run on ASP.NET Core 2 and still verify authorization using IdentityServer4. My IdentityServer sample project is taking the longest to update so I would expect at least one or two more posts on the process as each of the projects gets upgraded.

Identity Server: API Migration to ASP.NET Core 2 Read More »

All Migrations are not Created Equal

While trying to deploy my sample Identity Server set of applications to Azure I got the following error when the Entity Framework migrations attempted to run.

System.Data.SqlClient.SqlException (0x80131904): Column 'Id' in table 'AspNetRoles' is of a type that is invalid for use as a key column in an index

This was not something I would get when attempting to run locally, but it failed every time when using SQL Azure. Long store short is that the migrations that were trying to be applied were created when I was using Sqlite as a backing store (UseSqlite).

I deleted all the migrations and recreated them with the app being aware that it would be running on SQL Server (UseSqlServer) and all worked as it should. It makes total sense that the migrations would vary based on the data provider being used, but not something I had really thought about. Not something I will forget again.

All Migrations are not Created Equal Read More »

Unable to create an object of type ‘ApplicationDbContext’. Add an implementation of ‘IDesignTimeDbContextFactory

Forgive the long title, but this is an issue I have been fighting trying to upgrade an Identity Server 4 project to ASP.NET Core 2. There is an issue on GitHub dedicated to this exact error which can be found here. Before you go down the route of trying all the suggestions in the issue take a moment and make sure that nothing in the Startup class is doing anything that would try to hit the database with Entity Framework.

There is a nice section in the official migration docs titled “Move database initialization code” which I seemed to have missed. So before you head down any rabbit holes like I did make sure this isn’t what is causing your need to add an implementation of IdesignTimeDbContextFactory.

As stated in the migration docs move database related code out of the Configure function of the Startup class and into the Main function. The following is the example of this from the docs.

var host = BuildWebHost(args);

using (var scope = host.Services.CreateScope())
{
    var services = scope.ServiceProvider;

    try
    {
        // Requires using RazorPagesMovie.Models;
        SeedData.Initialize(services);
    }
    catch (Exception ex)
    {
        var logger = services.GetRequiredService<ILogger<Program>>();
        logger.LogError(ex, "An error occurred seeding the DB.");
    }
}

host.Run();

This will keep Entity Framework tooling from accidentally running code you didn’t expect.  With version 2 all the code in the Configure function gets run.

Unable to create an object of type ‘ApplicationDbContext’. Add an implementation of ‘IDesignTimeDbContextFactory‘ Read More »

Identity Server: External Authentication using Twitter

This post is going to cover adding authentication using Twitter to the same project that has been used in all of my IdentityServer examples. The same basic idea would apply to almost any third party authentication setup so this should give you a good starting point for any integration. The starting point of the code can be found here.

Create Twitter App

Before any code changes create a new application on Twitter via this page. Click Create New App to begin the process.

On the Create an application page enter all the requested information. Note that the website won’t allow a localhost address. If you don’t have a real address for your application just enter a random URL as I did here. When finished click Create your Twitter application.

Now that we have an application click on the Keys and Access Tokens tab. We will need both the Consumer Key and Consumer Secret when we get to the Identity Application.

Identity Application Changes

Now that we have a Twitter application ready to go let us dive into the changes needed to the Identity Application. The first step is to add a reference to Microsoft.AspNetCore.Authentication.Twitter via NuGet.

Next in the ConfigureServices function of the Startup class after app.UseIdentityServer() add the following.

app.UseTwitterAuthentication(new TwitterOptions
{
    AuthenticationScheme = "Twitter",
    DisplayName = "Twitter",
    SignInScheme = "Identity.External",
    ConsumerKey = Configuration["Authentication:Twitter:ConsumerKey"],
    ConsumerSecret = Configuration["Authentication:Twitter:ConsumerSecret"]
});

The first three options should a straight forward enough. The next two are the values from the Twitter application I mentioned above. In this example, I am storing the values using User Secrets which get pulled out of configuration. For more details on how to set up secrets, you can see this post.

The above are all the changes required. The Identity Application will now allow users to auth using Twitter.

Logging in using Twitter

As you can see below the login page now has a button for Twitter.

When the user chooses to log in using Twitter they are shown the following page where they must approve access to their Twitter account from your application.

If this is the first time a user has logged in with Twitter they will be prompted to enter an email address to finish registration.

Wrapping up

As you can see adding external authentication is super simple. Check out the Microsoft Docs on Twitter Auth (ASP.NET Core 2.0 so look out for differences if you are not on the preview bits) and IdentityServer Docs on External Auth for more information.

The finished code can be found here.

 

Identity Server: External Authentication using Twitter Read More »