ASP.NET Core

ASP.NET Core 3.1 Web.config Transform for Production

I recently upgraded an application from ASP.NET Core 2.2 to 3.1 around the same time the application got moved to a new server. Side note, don’t make two large changes like that at the same time if you can help it as it always makes tracking down the cause of the issue much harder.  The application in question was created using the ASP.NET Core React template initially.

The Error

After the changes above the site started returning the following error.

HTTP Error 500.0 – ANCM In-Process Handler Load Failue

To diagnose the issue I enabled standard out logging by changing the stdoutLogEnabled to true. The following is the line from the application’s web config with the logging enabled.

<aspNetCore processPath="dotnet" arguments=".\YourApplication.dll" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout">

The Cause

The logging showed that the application was trying to start the React part of the application using the React Development Server, which uses npm. Here is the related code from the Configure function of the Startup class.

app.UseSpa(spa =>
           {
               spa.Options.SourcePath = "ClientApp";

               if (env.IsDevelopment())
               {
                   spa.UseReactDevelopmentServer(npmScript: "start");
               }
           });

As you can see from the highlighted area the Reac Development Server should only be used when the environment is set to development and sure enough, the web.config has environment variable for ASPNETCORE_ENVIRONMENT and the value is Development as you can see in the following example.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet" arguments="YourApplication.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="InProcess">
        <environmentVariables>
          <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
        </environmentVariables>
      </aspNetCore>
    </system.webServer>
  </location>
</configuration>

A Fix

My knee jerk reaction was to find a way to get the value of that variable changed when the application is published in release mode. This helped me find the Microsoft docs for Transform web.config.

For this fix, I used a build configuration base transform. To do this I added a new file named web.Release.config. With this new file present, the transforms in the file will be executed when a release build is run. The following is the transform I used to get ASPNETCORE_ENVIRONMENT set to Production.

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <location>
    <system.webServer>
      <aspNetCore>
        <environmentVariables>
          <environmentVariable xdt:Transform="Replace" xdt:Locator="Match(name)" name="ASPNETCORE_ENVIRONMENT" value="Production" />
        </environmentVariables>
      </aspNetCore>
    </system.webServer>
  </location>
</configuration>

It is important that the structure of your transforms match what is in your actual web.config or the transform won’t be able to locate the element that needs to be transformed which in this case we are looking for an element under configuration/location/system.webServer/aspNetCore/enviromentVariables.

In our example, we are telling the transform we want to replace the element  (xdt:Transform=”Replace”) that matches the name (xdt:Locator=”Match(name)”) ASPNETCORE_ENVIRONMENT with the value Production.

Wrapping Up

This is just one small example of what can be done with web.config transforms. The official docs gave me a general high-level idea of what transforms can do, but wasn’t super helpful for what I needed to do. If the docs don’t cover your use case get ready to do a fair amount of searching.

Side note in the application I was referencing above it turns out that the web.config in the published for .NET Core 2.1 didn’t contain a value for ASPNETCORE_ENVIRONMENT which was why it wasn’t an issue before.

ASP.NET Core 3.1 Web.config Transform for Production Read More »

Using NSwag to Generate an Aurelia Client for an ASP.NET Core 3.1 API

This week we are going to add an Aurelia project that will utilize the contacts API we created a few weeks ago using a client-generated by NSwag. This post is part of the revamp of the ASP.NET Core Basics repo that was kicked off when .NET Core 3.0 was released which is now targeting .NET Core 3.1. For details on how the associated samples got to their current point check out the following posts.

Swagger/OpenAPI with NSwag and ASP.NET Core 3
ASP.NET Core 3: Add Entity Framework Core to Existing Project
New Razor Pages Project Backed with an API
Using NSwag to Generate Angular Client for an ASP.NET Core 3 API
Using NSwag to Generate React Client for an ASP.NET Core 3 API
Using NSwag to Generate Blazor Server Client for an ASP.NET Core 3.1 API
Using NSwag to Generate a Vue Client for an ASP.NET Core 3.1 API

The sample code before any changes from this post can be found here.


 

Create the Aurelia Project

As with Vue there is no .NET CLI template from Microsoft that has Aurelia support so to crate the Aurelia project we will be using the Aurelia CLI. Before getting started ensure you have npm installed.

Install the Aurelia CLI using the following command from a command prompt.

npm install -g aurelia-cli

Next, use the following command to start the project creation process using the Aurelia CLI. Keep in mind that the CLI creates a directory with the project name.

au new

The above will result in a walkthrough of the project creation process. First is the name of the project, contacts-aurelia in this case. Next is the setup of the project and here we will be using the Default TypeScript App.

Finally, select how you would like to manage dependencies. The sample project is using npm, but Yarn is also an option. If you do go with Yarn some of the following steps will need the npm commands translated to Yarn commands.

After the project creation process is complete use the following command to change to the new directory created for the project.

cd contacts-aurelia

Now the project needs a few more dependencies installed. We are going to install a couple of UI related items, Bootstrap and Font Awesome, as well as the Aurelia Fetch Client which we will need to hit our API.

npm install bootstrap
npm install font-awesome
npm install aurelia-fetch-client

The application that the Aurelia CLI outputs is very basics so the Aurelia docs for creating a to-do application and creating a contact manager were used to build the basics of the sample application. I will be coving the contact related bits of the UI, but the application stops short of implementing the save functionality at this point.

Use NSwagStudio to Generate an API Client

NSwag provides multiple options for client generation including a CLI, code, or a Windows application. This post is going to use the Windows application which is called NSwagStudio. NSwagStudio can be downloaded and installed from here.

Next, make sure your API is running and get the URL of its OpenAPI/Swagger specification URL. For example, using a local instance of the sample solution’s Contacts API the URL is https://localhost:5001/swagger/v1/swagger.json. If you are using the Swagger UI you can find a link to your swagger.json under the API title.

Now that we have the OpenAPI/Swager specification URL for the API switch over to NSwagStudio. The application will open with a new document ready to go. There are a few options we will need to set. First, select the OpenAPI/Swagger Specification tab and enter your API’s specification URL in the Specification URL box.

In the Outputs section check the TypeScript Client checkbox and then select the TypeScript Client tab. There are a lot of options to play with, the highlighted options are the ones that are important for this sample. For Template, we just need an Aurelia based client. The final option that needs to be set is the Output file path and this is the location you want the generated file to be. I output to the Aurelia project directory under /src/contactApi.ts. After all the options are set click Generate Files.

Create UI and Use Generated Client

Again the UI bit mostly comes from the docs, but I’m going to show the bits for the contact list here and the rest of the UI you can look at the sample code. All of the following will be taking place in the src directory of the Aurelia project.

First, add a file named contact-list.html which will hold the template for the UI of the contact list with the following contents. This is a mix of HTML and Aurelia’s syntax. We aren’t really going into the Aurelia specific bits, but even if you are new to Aurelia this should be readable.

<template>
  <div class="contact-list">
    <ul class="list-group">
      <li repeat.for="contact of contacts" class="list-group-item ${contact.id === $parent.selectedId ? 'active' : ''}">
        <a route-href="route: contacts; params.bind: {id:contact.id}" click.delegate="$parent.select(contact)">
          <h4>${contact.firstName} ${contact.lastName}</h4>
          <p>${contact.email}</p>
        </a>
      </li>
    </ul>
  </div>
</template>

Next, add a contact-list.ts file which is what the template from above will be bound to. The lines specific to the usage of the NSwag generated client are highlighted.

import {ContactsClient, Contact} from './contactsApi';
import {inject} from 'aurelia-framework';

@inject(ContactsClient)
export class ContactList {
  contacts: Contact[];
  api: ContactsClient;
  selectedId: any;
  
  constructor(api: ContactsClient) {
    this.api = api;
    this.contacts = [];
  }

  created() {
    this.api.getContacts().then(contacts => this.contacts = contacts);
  }

  select(contact) {
    this.selectedId = contact.id;
    return true;
  }
}

As you can see from the above Aurelia is injecting an instance of the ContactsClient via the class’s construction and then that client is used in the created function to call the API client’s getContacts function and using the resulting data from the API to replace the contacts field with the results of the API call.

The application is displaying the contact list in app.html via the contact-list element. The import and usage of the contact list component are highlighted in the following chunk of code.

<template>
  <require from="./styles.css"></require>
  <require from="./contact-list"></require>

  <nav class="navbar navbar-light bg-light fixed-top" role="navigation">
    <a class="navbar-brand" href="#">
      <i class="fa fa-user"></i>
      <span>Contacts</span>
    </a>
  </nav>

  <div class="container">
    <div class="row">
      <contact-list class="col-md-4"></contact-list>
      <router-view class="col-md-8"></router-view>
    </div>
  </div>
</template>

At this point, I tried out the application and it wasn’t pulling back any data. After doing some digging in the network tab of my browser’s dev tool I noticed that the API call was missing the base part of the URL. This hasn’t come up before for the other times I have used the NSwag generated client and if you look at the constructor of the client it defaults the base URL to the endpoint that was used to generate the client, see the following code.

constructor(baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
    this.http = http ? http : <any>window;
    this.baseUrl = baseUrl ? baseUrl : "https://localhost:5001";
}

It turns out that the Aurelia dependency injection system calls the constructor with an empty string instead of null. One option would have been to change the above constructor to handle an empty string, but that would mean any time the client got regenerated I would have to remember to follow it up with the constructor modification which would be too easy to screw up. After some digging, I found out that Aurelia provides a way to control how an instance of a class is created. Open main.ts and make the following highlighted changes. I’m injecting the URL, but using null instead would also work and the base URL from the ContactClient would get used.

import { HttpClient } from 'aurelia-fetch-client';
import {Aurelia} from 'aurelia-framework'
import * as environment from '../config/environment.json';
import {PLATFORM} from 'aurelia-pal';
import 'bootstrap/dist/css/bootstrap.css';
import 'font-awesome/css/font-awesome.css';
import { ContactsClient } from 'contactsApi';

export function configure(aurelia: Aurelia) {
  aurelia.use
    .standardConfiguration()
    .feature(PLATFORM.moduleName('resources/index'))
    .instance(ContactsClient, 
              new ContactsClient("https://localhost:5001",
                                 aurelia.container.get(HttpClient)));

  aurelia.use.developmentLogging(environment.debug ? 'debug' : 'warn');

  if (environment.testing) {
    aurelia.use.plugin(PLATFORM.moduleName('aurelia-testing'));
  }

  aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName('app')));
}

After all the change from a command prompt set to the root of the Aurelia project, you can use the following command to run the application. If you drop the open it will run the application without opening a browser.

au run --open

Wrapping Up

As always NSwag makes it very easy to create a client to interact with an API. Hopefully, this was useful even if my Aurelia code might not be idiomatic.

The sample projects after all the changes in this post can be found here.

Using NSwag to Generate an Aurelia Client for an ASP.NET Core 3.1 API Read More »

Using NSwag to Generate a Vue Client for an ASP.NET Core 3.1 API

This week we are going to add a Vue project that will utilize the contacts API we created a few weeks ago using a client-generated by NSwag. This post is part of the revamp of the ASP.NET Core Basics repo that was kicked off when .NET Core 3.0 was released which is now targeting .NET Core 3.1. For details on how the associated samples got to their current point check out the following posts.

Swagger/OpenAPI with NSwag and ASP.NET Core 3
ASP.NET Core 3: Add Entity Framework Core to Existing Project
New Razor Pages Project Backed with an API
Using NSwag to Generate Angular Client for an ASP.NET Core 3 API
Using NSwag to Generate React Client for an ASP.NET Core 3 API
Using NSwag to Generate Blazor Server Client for an ASP.NET Core 3.1 API
Using NSwag to Generate a Vue Client for an ASP.NET Core 3.1 API

The sample code before any changes from this post can be found here.

Create the Vue Project

Unlike the rest of the projects in this series, there is no .NET CLI template from Microsoft that has Vue support so to crate the Vue project we will be using the Vue CLI. Before getting started ensure you have npm installed.

Install the Vue CLI using the following command from a command prompt.

npm install -g @vue/cli

Next, use the following command to start the project creation process using the Vue CLI. Keep in mind that the CLI creates a directory with the project name.

vue create contacts-vue

The above command kicks off a series of questions about the application. This sample is going to use TypeScript which means that the default can’t be used so we need to select Manually select features.

For the next question, we need to select TypeScript. I also included the Router and Linter / Formatter. I also found out later in the process that Babel was needed so feel free to select it on this question.

The project creation process asked a bunch more questions that I basically took the defaults on. Here is a screenshot of all the questions and the options I used.

Now that the project is created if we need to change directories to the one created in the above process.

cd contacts-vue

Use the following command to run the new project.

npm run serve

Use NSwagStudio to Generate an API Client

NSwag provides multiple options for client generation including a CLI, code, or a Windows application. This post is going to use the Windows application which is called NSwagStudio. NSwagStudio can be downloaded and installed from here.

Next, make sure your API is running and get the URL of its OpenAPI/Swagger specification URL. For example, using a local instance of the sample solution’s Contacts API the URL is https://localhost:5001/swagger/v1/swagger.json. If you are using the Swagger UI you can find a link to your swagger.json under the API title.

Now that we have the OpenAPI/Swager specification URL for the API switch over to NSwagStudio. The application will open with a new document ready to go. There are a few options we will need to set. First, select the OpenAPI/Swagger Specification tab and enter your API’s specification URL in the Specification URL box.

In the Outputs section check the TypeScript Client checkbox and then select the TypeScript Client tab. There are a lot of options to play with, the highlighted options are the ones that are important for this sample. First, make sure Module name and Namespace are both empty. I’m sure there is a way to get the client working with a module or namespace, but I didn’t have any luck.   For Template, we just need a Fetch based client. The final option that needs to be set is the Output file path and this is the location you want the generated file to be. I output to the Vue project directory under /src/apis/contactApi.ts. After all the options are set click Generate Files.

Create UI and Use Generated Client

Note that I haven’t touch Vue in a long time so the actually UI bits may or may not be the “proper” way to do this stuff in Vue, but it should be understandable enough that you can see how the API client is used. As with the other post in this same vein, we are going to create a contact list that gets its data from an API.

First, we are going to create a new component for the contact list in the /src/component directory with the filename of ContactList.vue with the following contents. The lines specific to the usage of the NSwag generated client are highlighted.

<template>
  <div>
    <table class="table table-striped" aria-labelledby="tabelLabel">
      <thead>
        <tr>
          <th>Name</th>
          <th>Address</th>
          <th>City</th>
          <th>State</th>
          <th>Postal Code</th>
          <th>Phone</th>
          <th>Email</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="contact in contacts" v-bind:key="contact.id">
          <td>{{contact.name}}</td>
          <td>{{contact.address}}</td>
          <td>{{contact.city}}</td>
          <td>{{contact.state}}</td>
          <td>{{contact.postalCode}}</td>
          <td>{{contact.phone}}</td>
          <td>{{contact.email}}</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import { ContactsClient, Contact } from '../apis/contactsApi'
@Component
export default class HelloWorld extends Vue {
  name: string = 'ContactList';
  contacts: Contact[] = [];
  private created () {
    let client = new ContactsClient()
    client.getContacts().then(data => (this.contacts = data))
  }
}
</script>

<style scoped>
</style>

As you can see from the created function above we are creating a new instance of the ContactsClient and calling its getContacts function and using the data we get back from the API to replace the contacts field with the results of the API call.

Next, we are going to create a ContactList.vue under the /src/views directory with the following code. This is basically a wrapper around the component we created above.

<template>
  <div>
    <ContactListComponent/>
  </div>
</template>

<script>
import ContactListComponent from '@/components/ContacList'
export default {
  name: 'contactList',
  components: {
    ContactListComponent
  }
}
</script>

Now that we have our view ready we need to add a link to the application’s navigation so a user can get to the contact list. Open App.vue and a router link to the nav div for the contact list.

<div id="nav">
    <router-link to="/">Home</router-link> |
    <router-link to="/contactList">Contacts</router-link> |
    <router-link to="/about">About</router-link>
</div>

Now we need to add the new component to the routes for the application. Open index.ts in the /src/router directory and add an import for the contact list view.

import ContactList from '../views/ContactList.vue'

Finally, add the contact list to the routes array.

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/contactList',
    name: 'contactList',
    component: ContactList
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

Wrapping Up

As always NSwag makes it very easy to create a client to interact with an API. Hopefully, this was useful even if my Vue code might not be idiomatic.

The sample projects after all the changes in this post can be found here.

Using NSwag to Generate a Vue Client for an ASP.NET Core 3.1 API Read More »

Using NSwag to Generate Blazor Server Client for an ASP.NET Core 3.1 API

This week we are going to add a Blazor Server project that will utilize the contacts API we created a few weeks ago. This post is part of the revamp of the ASP.NET Core Basics repo that was kicked off when .NET Core 3.0 was released. For details on how the associated sample got to the current point in the application check out the following posts.

Swagger/OpenAPI with NSwag and ASP.NET Core 3
ASP.NET Core 3: Add Entity Framework Core to Existing Project
New Razor Pages Project Backed with an API
Using NSwag to Generate Angular Client for an ASP.NET Core 3 API
Using NSwag to Generate React Client for an ASP.NET Core 3 API
Using NSwag to Generate Blazor Server Client for an ASP.NET Core 3.1 API
Using NSwag to Generate a Vue Client for an ASP.NET Core 3.1 API

The sample code before any of the changes in this post can be found here.

Create the Blazor Server Project

Add a new directory for the Blazor Server project and then open a terminal set to that directory. The following command can be used to create a new Blazor Server project.

dotnet new blazorserver

Next, use the following command to add the new project to the solution file which is in the root of the repo. Your filenames and paths will vary of course.

dotnet sln ..\..\BasicsRefresh.sln add ContactsBlazorServerApp.csproj

Using NSwageStudio to Generate an API Client

NSwag provides multiple options for client generation including a CLI option, code, and a Windows application. This post is going to use the Windows application which is called NSwagStudio. Download and install NSwagStudio from here.

Next, make sure your API is running and get the URL of its OpenAPI/Swagger specification URL. For example, I am using a local instance of my API and the URL I need is https://localhost:5001/swagger/v1/swagger.json. If you are using the Swagger UI you can find a link to your swagger.json under the API title.

Now that we have the OpenAPI/Swager specification URL for the API switch over to NSwagStudio. The application will open with a new document ready to go. There are a few options we will need to set. First, we want to use the NetCore30 Runtime. Next, select the OpenAPI/Swagger Specification tab and enter your API’s specification URL in the Specification URL box.

In the Outputs section check the CSharp Client checkbox and then select the CSharp Client tab. For this example, we are taking the defaults for all of the options except for Namespace, which is set to ContactsApi, Generate interfaces for Client classes, which should be check, and Output file path, which is only needed if you use the Generate Files option. Click the Generate Files button and NSwagStudio will create a file that contains all the code needed to access the API described in the OpenAPI/Swager specification selected in the Input section.

The Generate Outputs button can be used if to populate the Output tab with the same code that the Generate Files process creates which provides a nice way to play with settings to and see the output without having to open another file.

Setting Up the Generated Client in the Blazor Server Project

In the sample project, create an APIs directory and dropped the ContactsApi.cs created with NSwagStudio there. The files generated with NSwagStudio are expecting JSON.NET to be present so the sample project will need a reference to the Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet package.

With the client-generated and in our local Apis directory in the Razor Pages project we can now work on getting it configured and registered for use in our new project. First, open the apppsetting.json file and add a setting for the URL of our API, which is the ContactsApi value in the following sample.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ContactsApi": "https://localhost:5001"
}

Now that the project has the configuration change and a reference to JSON.NET in the ConfigureServices function of the Startup class we need to tell the app to make JSON.NET available via dependency injection by using AddNewtonsoftJson as in the following example.

services.AddRazorPages()
        .AddNewtonsoftJson();

Also in the ConfigureServices function, we need to register our API client.

services.AddHttpClient<IContactsClient, 
                       ContactsClient>(client => 
         client.BaseAddress = new Uri(Configuration.GetSection("ContactsApi").Value));

Create the UI and Usage of the Generated Client

Now that all the setup work is done we can add the contact list UI which will show the usage of the API client. The following is the full code which for the sample is in a new ContactList.razor file in the Pages directory. The specific lines related to the API client are highlighted.

@page "/contactlist"

@using Apis
@inject IContactsClient ContactClient

<h1>Contact List</h1>

@if (_contacts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table className='table table-striped' aria-labelledby="tabelLabel">
        <thead>
            <tr>
                <th>Name</th>
                <th>Address</th>
                <th>City</th>
                <th>State</th>
                <th>Postal Code</th>
                <th>Phone</th>
                <th>Email</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var contact in _contacts)
            {
                <tr>
                    <td>@contact.Name</td>
                    <td>@contact.Address</td>
                    <td>@contact.City</td>
                    <td>@contact.State</td>
                    <td>@contact.PostalCode</td>
                    <td>@contact.Phone</td>
                    <td>@contact.Email</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private ICollection<Contact> _contacts;

    protected override async Task OnInitializedAsync()
    {
        _contacts = await ContactClient.GetContactsAsync();
    }
}

Finally to add our new page to the navbar open the NavMenu.razor file found in the Shared directory. Add the following list item to the unordered list.

<li class="nav-item px-3">
    <NavLink class="nav-link" href="contactlist">
        <span class="oi oi-list" aria-hidden="true"></span> Contacts
    </NavLink>
</li>

Wrapping Up

As with the other posts I have been doing utilizing NSwag for client generation this process is pretty easy and simplifies API consumption.

The sample code in its final state can be found here.

Using NSwag to Generate Blazor Server Client for an ASP.NET Core 3.1 API Read More »

Migration from ASP.NET Core 3.0 to 3.1

On December 3rd .NET Core 3.1 was released which included a new release of ASP.NET Core 3.1 and Entity Framework Core 3.1. This post is going to walk through updating the Contacts API project from the refreshed ASP.NET Basics series. All the changes I made came from Microsoft’s Migrate from ASP.NET Core 3.0 to 3.1 doc.

The code before any changes can be found here.

Installation

If you are a Visual Studio user you can get .NET Core 3.0 by installing at least Visual Studio 16.4. For those not using Visual Studio, you can download and install .NET Core 3.1 SDK from here. As with previous versions, the SDK is available for Windows, Linux, and Mac.

After installation is complete you can run the following command from a command prompt to see all the versions of the .NET Core SDK you have installed.

dotnet --list-sdks

You should see 3.1.100 listed at a minimum.

Project File Changes

Right-click on the project and select Edit projectName.csproj.

Change the TargetFramework to netcoreapp3.1.

Before:
<TargetFramework>netcoreapp3.0</TargetFramework>

After
<TargetFramework>netcoreapp3.1</TargetFramework>

Next, update all your packages to the new versions. This is going to vary greatly based on your project. This can be done manually in the csproj file or via the NuGet UI if you are using Visual Studio. The following are the changes from the sample project.

Before:
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.0.0">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.0.0">
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="1.2.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0" />
<PackageReference Include="NSwag.AspNetCore" Version="13.1.3" />

After:
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.0">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.0">
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.0" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="1.3.2" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.0" />
<PackageReference Include="NSwag.AspNetCore" Version="13.1.6" />

Wrapping Up

The move from 3.0 to 3.1 is drop-dead simple which is not surprising since it has only been a few months since the release of 3.0. It is important to move to 3.1 as soon as you can since it is the long term service version and will be supported for at least the next 3 years where 3.0 will lose support within months.

Migration from ASP.NET Core 3.0 to 3.1 Read More »

Log Requests and Responses in ASP.NET Core 3

This post is going to be a refresh of the Log Requests and Responses in ASP.NET Core post which no longer works more modern versions of ASP.NET Core. For the most part, this post will exactly match the original but with the code bits updated.

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 than I had expected to deal with the request and response bodies.

Middleware

In ASP.NET Core middleware are the components that make up the HTTP pipeline that handles requests and responses for the application. Each piece of middleware called has the option to do some processing on the request before calling the 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 HTTP pipeline for an application is set in the Configure function of the Startup class. Run, Map and Use are the three types of middleware available. 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 using the class route.

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

The class will need a constructor that takes two arguments both will be provided by ASP.NET Core’s dependency injection system. The first is a RequestDelegate which will be the next piece of middleware in the pipeline. The second is an instance of 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 that 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 the request

     await _next(context);

     //code dealing with the 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.cs file and add the following line to the Configure function.

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 start of the pipeline.

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 than I expected, but thankfully I found this by Sul Aga which really helped me work through the issues I was having along with a lot of feedback on the original version of this post.

One of the bits of feedback on the original version of this post was about a potential memory leak and using recyclable memory streams. First, add a NuGet reference to the Microsoft.IO.RecyclableMemoryStream package. Next, we will add a class-level variable to hold an instance of a RecyclableMemoryStreamManager which we will create in the constructor. The following is an updated class view with these changes as well as changes to the Invoke function and stubs for the logging methods.

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

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

    public async Task Invoke(HttpContext context)
    {
        await LogRequest(context);
        await LogResponse(context);
    }
  
    private async Task LogRequest(HttpContext context) {}
    private async Task LogResponse(HttpContext context) {}
}

First, we are going to look at the LogRequest function, and a helper function it uses.

private async Task LogRequest(HttpContext context)
{
    context.Request.EnableBuffering();

    await using var requestStream = _recyclableMemoryStreamManager.GetStream();
    await context.Request.Body.CopyToAsync(requestStream);
    _logger.LogInformation($"Http Request Information:{Environment.NewLine}" +
                           $"Schema:{context.Request.Scheme} " +
                           $"Host: {context.Request.Host} " +
                           $"Path: {context.Request.Path} " +
                           $"QueryString: {context.Request.QueryString} " +
                           $"Request Body: {ReadStreamInChunks(requestStream)}");
    context.Request.Body.Position = 0;
}

private static string ReadStreamInChunks(Stream stream)
{
    const int readChunkBufferLength = 4096;

    stream.Seek(0, SeekOrigin.Begin);

    using var textWriter = new StringWriter();
    using var reader = new StreamReader(stream);

    var readChunk = new char[readChunkBufferLength];
    int readChunkLength;

    do
    {
        readChunkLength = reader.ReadBlock(readChunk, 
                                           0, 
                                           readChunkBufferLength);
        textWriter.Write(readChunk, 0, readChunkLength);
    } while (readChunkLength > 0);

    return textWriter.ToString();
}

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

The next function is LogResponse which is used to execute the next bit of middleware in the pipeline, using await _next(context) and then logging the response body after the rest of the pipeline has run.

private async Task LogResponse(HttpContext context)
{
    var originalBodyStream = context.Response.Body;

    await using var responseBody = _recyclableMemoryStreamManager.GetStream();
    context.Response.Body = responseBody;

    await _next(context);

    context.Response.Body.Seek(0, SeekOrigin.Begin);
    var text = await new StreamReader(context.Response.Body).ReadToEndAsync();
    context.Response.Body.Seek(0, SeekOrigin.Begin);

    _logger.LogInformation($"Http Response Information:{Environment.NewLine}" +
                           $"Schema:{context.Request.Scheme} " +
                           $"Host: {context.Request.Host} " +
                           $"Path: {context.Request.Path} " +
                           $"QueryString: {context.Request.QueryString} " +
                           $"Response Body: {text}");

    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. I don’t know how much this affects performance and would make sure to study how it scales before using it in a production environment.

Wrapping up

I hope this updated post turns out to be as helpful as the original seemed to be. This round I do have the code in a GitHub repo and the commit with the related changes can be found here.

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

Using NSwag to Generate React Client for an ASP.NET Core 3 API

This week we are going to add a React project that will utilize the contacts API we created a few weeks ago. This post is part of the revamp of the ASP.NET Core Basics repo that was kicked off when .NET Core 3.0 was released. For details on how the associated sample got to the current point in the application check out the following posts.

Swagger/OpenAPI with NSwag and ASP.NET Core 3
ASP.NET Core 3: Add Entity Framework Core to Existing Project
New Razor Pages Project Backed with an API
Using NSwag to Generate Angular Client for an ASP.NET Core 3 API
Using NSwag to Generate React Client for an ASP.NET Core 3 API
Using NSwag to Generate Blazor Server Client for an ASP.NET Core 3.1 API
Using NSwag to Generate a Vue Client for an ASP.NET Core 3.1 API

I realize that using an ASP.NET Core backed React project for this sample is overkill and a raw React application would have been all that is needed. I chose to use the ASP.NET Core template as a base for all the projects in this series to be consistent. After the initial application creation, you can think of this example as setting up access to a secondary API in addition to the application’s main API if that helps or the generated client on the React side could be used to wrap the API generated by the template.

The sample code before any of the changes in this post can be found here.

Create the React Project

Add a new directory for the React project and then open a terminal set to that directory. The following command can be used to create a new React project. The target framework isn’t required, but I have a preview of .NET Core 3.1 installed and I wanted to make sure this project is targeting .NET Core 3.0.

dotnet new react -f netcoreapp3.0

Next, use the following command to add the new project to the solution file which is in the root of the repo. Your filenames and paths will vary if you are not using the sample code of course.

dotnet sln ..\..\BasicsRefresh.sln add ContactsReact.csproj

Use NSwagStudio to Generate React Client

NSwag provides multiple options for client generation including a CLI, code, and a Windows application. This post is going to use the Windows application which is called NSwagStudio. Download and install NSwagStudio from here.

Next, make sure your API is running and get the URL of its OpenAPI/Swagger specification URL. For example, I am using a local instance of my API and the URL I need is https://localhost:5001/swagger/v1/swagger.json. If you are using the Swagger UI you can find a link to your swagger.json under the API title.

Now that we have the OpenAPI/Swager specification URL for the API switch over to NSwagStudio. The application will open with a new document ready to go. There are a few options we will need to set. First, select the OpenAPI/Swagger Specification tab and enter your API’s specification URL in the Specification URL box.

In the Outputs section check the TypeScript Client checkbox and then select the TypeScript Client tab. There are a lot of options to play with, but I highlighted the options that were important for this sample. First, make sure Module name and Namespace are both empty. I’m sure there is a way to get the client working with a module or namespace, but I didn’t have any luck.   For Template, we just need a Fetch based client. The final option that needs to be set is the Output file path and this is the location you want the generated file to be. I output to the React project directory under ClientApp\src\app\components\contactApi.ts. After all the options are set click Generate Files.

Create UI and Use Generated Client

Once the above is done once you switch back to Visual Studio you should see the following prompt to add the Microsoft.TypeScript.MSBuild NuGet package. The React template doesn’t use TypeScript and NSwag doesn’t have an option to generate a plain JavaScript client so adding this package will allow the build process to take our TypeScript client and convert it to JavaScript. There is an open issue requesting a JavaScript generator.

The sample API is for contact management so the UI we are going to build is to display a contact list. In the ClientApp/src/component directory add a new file named ContactList.js with the following contents. The lines specific to the usage of the NSwag generated client are highlighted.

import React, { Component } from 'react';
import { ContactsClient } from './contactsApi';  

export class ContactList extends Component {
    static displayName = ContactList.name;

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

    componentDidMount() {
        this.populateContactData();
    }

    static renderContactsTable(contacts) {
        return (
            <table className='table table-striped' aria-labelledby="tabelLabel">
                <thead>
                    <tr>
                        <th>Name</th>
                        <th>Address</th>
                        <th>City</th>
                        <th>State</th>
                        <th>Postal Code</th>
                        <th>Phone</th>
                        <th>Email</th>
                    </tr>
                </thead>
                <tbody>
                    {contacts.map(contact =>
                        <tr key={contact.id}>
                            <td>{contact.name}</td>
                            <td>{contact.address}</td>
                            <td>{contact.city}</td>
                            <td>{contact.state}</td>
                            <td>{contact.postalCode}</td>
                            <td>{contact.phone}</td>
                            <td>{contact.email}</td>
                        </tr>
                    )}
                </tbody>
            </table>
        );
    }

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

        return (
            <div>
                <h1 id="tabelLabel" >Contacts</h1>
                {contents}
            </div>
        );
    }

    async populateContactData() {
        let client = new ContactsClient();
        client.getContacts()
              .then(data => this.setState({ contacts: data, loading: false }));
    }
}

As you can see from the populateContactData code above we are creating a new instance of the ContactsClient and calling its getContacts function and using the data we get back from the API to set the state of the component with the data return from the API.

Now that the contact list is ready it needs a link in the navbar. First, in the App.js file, we need to add the contact list to the router. The following is the full file with the added lines highlighted.

import React, { Component } from 'react';
import { Route } from 'react-router';
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';

import './custom.css'

export default class App extends Component {
  static displayName = App.name;

  render () {
    return (
      <Layout>
        <Route exact path='/' component={Home} />
        <Route path='/contacts' component={ContactList} />
        <Route path='/counter' component={Counter} />
        <Route path='/fetch-data' component={FetchData} />
      </Layout>
    );
  }
}

Now to make to add a Contacts link to the navbar open the NavMenu.js file and add the following to the with the other nav items.

<NavItem>
    <NavLink tag={Link} className="text-dark" to="/contacts">Contacts</NavLink>
</NavItem>

Wrapping  Up

I had a bit more trouble getting the NSwag client working this round, but that was more due to my shallow knowledge with React than a problem with NSwag.

The sample projects after all the changes in this post can be found here.

Using NSwag to Generate React Client for an ASP.NET Core 3 API Read More »

Using NSwag to Generate Angular Client for an ASP.NET Core 3 API

This week we are going to add an Angular project that will utilize the API we created a few weeks ago. This post is part of the revamp of my ASP.NET Core Basics repo that I kicked off when .NET Core 3.0 was released. For details on how we got to the current point in the application check out the following posts.

Swagger/OpenAPI with NSwag and ASP.NET Core 3
ASP.NET Core 3: Add Entity Framework Core to Existing Project
New Razor Pages Project Backed with an API
Using NSwag to Generate Angular Client for an ASP.NET Core 3 API
Using NSwag to Generate React Client for an ASP.NET Core 3 API
Using NSwag to Generate Blazor Server Client for an ASP.NET Core 3.1 API
Using NSwag to Generate a Vue Client for an ASP.NET Core 3.1 API

Do note that I realize that using an ASP.NET Core backed Angular project for this sample is overkill and a plain Angular application would have been all that is needed, but I wanted to use the ASP.NET Core template as a base for all the projects in this series. After the initial application creation, you can think of this example as setting up access to a secondary API in addition to the application’s main API if that helps.

The sample code before any of the changes in this post can be found here.

API Changes

Before we get to the actual Angular side of this post we are going to update the associated API to accept all cross-origin resource sharing (CORS) requests. The ASP.NET Core setup has a lot of options and I recommend being me explicit about what your API will accept if you can. Check out the official Microsoft CORS docs for more information.

All the changes needed will be in the Startup class of the API project. The CORS setup is policy-based and each policy needs a name that I stored in the following class level constant.

private const string AllowAllCors = "AllowAll";

In the ConfigureServices function add the following to register the CORS policy. Again be more restrictive with your policy if you can but for this example, we are opening up the API to allow any request.

services.AddCors(options =>
                 {
                     options.AddPolicy(AllowAllCors,
                                       builder =>
                                       {
                                           builder.AllowAnyHeader();
                                           builder.AllowAnyMethod();
                                           builder.AllowAnyOrigin();
                                       });
                 });

Finally, in the Configure function add the following to get CORS added to the HTTP pipeline processing. I’m not 100% sure if it matters where you added it in the pipeline, but I added it close to the front. I included a bit pipeline in the sample app for reference.

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

app.UseCors(AllowAllCors);

app.UseHttpsRedirection();

That is all the changes needed for the API, next we will create a new Angular project.

Create an Angular Project

Add a new directory for the application and then in a terminal navigate to that directory. Then the following command can be used to create the new Angular project. The target framework isn’t required, but I have a preview of .NET Core 3.1 installed and I wanted to make sure this project is targeting .NET Core 3.0.

dotnet new angular -f netcoreapp3.0

Next, use the following command to add the new project to the solution file which is in the root of the repo. Your filenames and paths could vary if you can’t using the same code of course.

dotnet sln ..\..\BasicsRefresh.sln add ContactsAngular.csproj

Use NSwagStudio to Generate Angular Client

NSwag provides multiple options for client generation including a CLI option, code, and a Windows application. This post is going to use the Windows application which is called NSwagStudio. Download and install NSwagStudio from here.

Next, make sure your API is running and get the URL of its OpenAPI/Swagger specification URL. For example, I am using a local instance of my API and the URL I need is https://localhost:5001/swagger/v1/swagger.json. If you are using the Swagger UI you can find a link to your swagger.json under the API title.

Now that we have the OpenAPI/Swager specification URL for the API switch over to NSwagStudio. The application will open with a new document ready to go. There are a few options we will need to set. First, select the OpenAPI/Swagger Specification tab and enter your API’s specification URL in the Specification URL box.

In the Outputs section check the TypeScript Client checkbox and then select the TypeScript Client tab. There are a lot of options to play with, but I highlighted the ones I changed to generate the client for this sample. First I entered a Module name so the generated code will all be in that module. For Template, it is very important to select Angular so that the resulting code will be set up for Angular’s dependency injection. Also, make sure and change the Injection token type to InjectionToken if you are on a newer version of Angular. The final option that needs to be set is the Output file path and this is the location you want the generated file to be. I output the Angular project directory under ClientApp\src\app\apis\contactApi.ts. After all the options are set click Generate Files.

For more information on generating Angular clients check the official docs on the subject.

Create UI and Use Generated Client

The sample API is for contact management so the UI we are going to build is to display a contact list. The new components are going to go in a new contacts directory under ClientApp\src\app. In this directory, we will need two new files one for the HTML, contact-list.component.html, and the other for the backing TypeScript class, contact-list.component.ts.

The following is the full content on the HTML file. I’m not going to go into the Angular specific bit in this post, but even if you don’t know Angular you will get the idea of what is going on. The rendered result will be a table of contacts.

<h1 id="tableLabel">Contacts</h1>

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

<table class='table table-striped' aria-labelledby="tableLabel" *ngIf="contacts">
  <thead>
    <tr>
      <th>Name</th>
      <th>Address</th>
      <th>City</th>
      <th>State</th>
      <th>Postal Code</th>
      <th>Phone</th>
      <th>Email</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let contact of contacts">
      <td>{{ contact.name }}</td>
      <td>{{ contact.address }}</td>
      <td>{{ contact.city }}</td>
      <td>{{ contact.state }}</td>
      <td>{{ contact.postalCode }}</td>
      <td>{{ contact.phone }}</td>
      <td>{{ contact.email }}</td>
    </tr>
  </tbody>
</table>

Next is the TypeScript class for the contact list. This is where you get to see the usage of the client that NSwag generated. The related lines are highlighted.

import { Component } from '@angular/core';
import { contacts as Contacts } from "../apis/contactApi";

@Component({
  selector: 'app-contact-list',
  templateUrl: './contact-list.component.html'
})
export class ContactListComponent {
  public contacts: Contacts.IContact[];

  constructor(contactsClient : Contacts.ContactsClient) {
    contactsClient.getContacts().subscribe(result => {
        this.contacts = result;
      },
      error => console.error(error));
  }
}

As you can see from the code above we are injecting the ContactClient and then calling its getContracts and assigning the results to the class’s local contacts variable.

Now that our components are built we need to register them with the application. These changes are in the app.module.ts file found in the ClientApp\src\app directory. The following is the full file excluding the imports that were existing with the changes for our contact related items highlighted.

import { ContactListComponent } from "./contacts/contact-list.component";
import { contacts } from "./apis/contactApi";

@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent,
    HomeComponent,
    CounterComponent,
    FetchDataComponent,
    ContactListComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule, 
    RouterModule.forRoot([
      { path: '', component: HomeComponent, pathMatch: 'full' },
      { path: 'contact-list', component: ContactListComponent },
      { path: 'counter', component: CounterComponent },
      { path: 'fetch-data', component: FetchDataComponent },
    ])
  ],
  providers: [contacts.ContactsClient],
  bootstrap: [AppComponent]
})
export class AppModule { }

The first change was to import both the ContactListComponent and contacts which is the contact client. Next, the ContactListComponent was added to the declarations array. Then we added the ContactListComponent to the RouterModule so that Angular will know how to get us to the contact list page. Finally, we added the ContractsClient to the providers array which will allow Angular to inject the client into our contact list component.

To add our contact list to the nav menu we need to change the nav-menu.component.html file in the ClientApp\src\app\nav-menu directory. Add the following list item to add a Contact link in the navbar.

<li class="nav-item" [routerLinkActive]="['link-active']">
  <a class="nav-link text-dark" [routerLink]="['/contact-list']"
    >Contacts</a
  >
</li>

Wrapping Up

I’m repeating myself, but NSwag’s client generation makes it very simple to get starting consuming APIs, but even over time being able to regenerate a client for an API and have any changes in that API ready to go is really nice.

The sample projects after all the changes in this post can be found here.

Using NSwag to Generate Angular Client for an ASP.NET Core 3 API Read More »

ASP.NET Core: An attempt was made to access a socket in a way forbidden by its access permissions

This morning I made some changes to a project for a future post. Minor stuff and nothing that should have caused issues, but when I tried to run the project I got the following error from Kestrel.

warn: Microsoft.AspNetCore.Server.Kestrel[0]
Unable to bind to https://localhost:5001 on the IPv4 loopback interface: ‘An attempt was made to access a socket in a way forbidden by its access permissions.’.
warn: Microsoft.AspNetCore.Server.Kestrel[0]
Unable to bind to https://localhost:5001 on the IPv6 loopback interface: ‘An attempt was made to access a socket in a way forbidden by its access permissions.’.
crit: Microsoft.AspNetCore.Server.Kestrel[0]
Unable to start Kestrel.
System.IO.IOException: Failed to bind to address https://localhost:5001.

I had limited time so I switched the project over to launch using IIS Express and hit run, but this resulted in the following error.

HTTP Error 500.35 – ANCM Multiple In-Process Applications in same Process

Switching back to Kestrel and changing the port number in the applicationUrl setting in the launchSettings.json file fixed the issue. Later I came back to the application and tried to track down what was using the same ports and couldn’t find anything. After a reboot, all worked fine with Kestrel and the original port numbers.

For the IIS Express error, I ended up having to delete the .vs directory which can be found in the same directory as your solution file if you are using Visual Studio 2019. Thanks to stackoverflow for this fix.

Wrapping Up

Not the post I set out to write this week, but hopefully this will save someone some searching in the future, more than likely myself.

ASP.NET Core: An attempt was made to access a socket in a way forbidden by its access permissions Read More »

New Razor Pages Project Backed with an API

This week we are going to add a Razor Pages project that will utilize the API we created a few weeks ago. This post is part of the revamp of my ASP.NET Core Basics repo that I kicked off when .NET Core 3.0 was released. For details on how we got to the current point in the application check out the following posts.

Swagger/OpenAPI with NSwag and ASP.NET Core 3
ASP.NET Core 3: Add Entity Framework Core to Existing Project

The code before the changes in this post can be found in this GitHub repo.

Razor Pages Project

Add a new directory for the application and then in a terminal navigate to that directory. Then the following command can be used to create the new Razor Pages application.

dotnet new webapp

Next, use the  following command to add the new project to the solution file which is in the root of the repo. Your filenames and paths could vary if you can’t using the same code of course.

dotnet sln ..\..\BasicsRefresh.sln add ContactsRazorPages.csproj

API Access Setup

For API access we are using NSwag to generate a client that our Razor Page application will use. For the actual creation of the API client see the following posts as this post will be skipping the actual client generation process.

Using NSwag to Generate C# Client Classes for ASP.NET Core 3
Use HTTP Client Factory with NSwag Generated Classes in ASP.NET Core 3

With the client-generated and in our local Apis directory in the Razor Pages project we can now work on getting it configured and registered for use in our new project. First, open the apppsetting.json file and add a setting for the URL of our API, which is the ContactsApi value in the following sample.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ContactsApi": "https://localhost:5001"
}

Next, in the ConfigureServices function of the Startup class we need to register a HTTP Client for our API.

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages()
            .AddNewtonsoftJson();

    services.AddHttpClient<IContactsClient, 
                           ContactsClient>(client => 
             client.BaseAddress = new Uri(Configuration.GetSection("ContactsApi").Value));
}

Add Pages

Now that our API access is set up we need to create pages that will allow users to interact with the API. To start add a Contacts directory to the existing Pages directory so all of the pages that deal with interacting with the Contacts API will be together.

CAUTION the next bit may or may not be helpful. I wanted to generate the UI for the Contact pages instead of having to manually create them using the scaffolding, but it needs Entity Framework to work and this new project doesn’t use Entity Framework. This section is going to walk through adding a temporary reference to the API project, since it does use Entity Framework, in order to generate the related UI. Feel free to skip this part if you want to manually create your associated UI.

In the API project add the following temparary changes to the ContactsDbContext class.

public ContactsDbContext() {}

protected override void OnConfiguring(DbContextOptionsBuilder options) => 
          options.UseSqlite("Data Source=app.db");

Now we need to add a temporary reference to the API project from the Razor Pages project. To do this right-click on the Dependencies node in Razor Pages project and select Add Reference.

In the Projects section check the box for the API project and click OK.

Now with the above in place, we can scaffold our UI. Right-click on the folder where you want the resulting UI to live, the Pages/Contacts directory in our case. From the menu select Add > New Scaffolded Item.

On the dialog that shows we want to select Razor Pages using Entity Framework (CRUD) and then click Add.

On the next screen we will be selecting the Model class and Data context class from the API project for the entity we are generating the UI for and then clicking Add.

After a few seconds, all the pages we need to view, create, edit, and delete contacts will exist. Now that we have our pages generated we need to remove the reference to the API project. To do this expand the Dependencies > Projects node and right-click on the API project and select Remove.

Also, revert the changes we made to the DbContext above.

Now that the reference to the API project is gone the Razor Pages application won’t build. This is expected as it was using some classes from the API project. We are going to walk through the edits needed to fix the issues in the Index page in the Contacts directory, but the same type of changes will be needed in all the generated classes.

First, we need to change some usings. Remove any Entity Framework related usings. Then change any related to the Contacts API to instead reference the API client local to the project.

Before:
using Microsoft.EntityFrameworkCore;
using ContactsApi.Data;
using ContactsApi.Models; 

After:
using Apis;

The other big item is to replace the injection of the Entity Framework DB Context with the API Client and update the related calls with calls to the API. The following is the IndexModel with the Entity Framework bits present.

public class IndexModel : PageModel
{
    private readonly ContactsApi.Data.ContactsDbContext _context;

    public IndexModel(ContactsApi.Data.ContactsDbContext context)
    {
        _context = context;
    }

    public IList<Contact> Contact { get;set; }

    public async Task OnGetAsync()
    {
        Contact = await _context.Contacts.ToListAsync();
    }
}

And here is the end result using the API Client.

public class IndexModel : PageModel
{
    private readonly IContactsClient _client;

    public IndexModel(IContactsClient client)
    {
        _client = client;
    }

    public IList<Contact> Contact { get;set; }

    public async Task OnGetAsync()
    {
        Contact = (await _client.GetContactsAsync()).ToList();
    }
}

And as stated above this kind of thing would need to be repeated for the other generated pages.

END CAUTION

Add to Navigation Bar

Now that we have our pages created we need to add a way for the user to get to them. To do this we are going to add a Contacts option to the navigation bar. Open the Pages/Shared/_Layout.cshtml file. The easiest way to locate where the change needs to go is to search for the text of one of the existing navigation links. The following is the links section with the new items added.

<ul class="navbar-nav flex-grow-1">
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
    </li>
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="" asp-page="Contacts/Index">Contacts</a>
    </li>
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
    </li>
</ul>

Wrapping Up

Using Nswag’s generated client makes it super simple to connect an application to an API, not that doing it manually is hard per se. Most of this post ended up being about my detour to generate the UI in the client application. Was it worth it? I’m not sure. I guess either way it is nice to know it is an option when you have the Entity Framework data available.

Here is the code in the final state from this post.

New Razor Pages Project Backed with an API Read More »