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.
Also published on Medium.