Blazor + EF Core: A Simple Web App Part 2

Morgan Kenyon
9 min readJul 8, 2019

--

Photo by Michael Mroczek on Unsplash

Welcome back to part 2 describing how to use Blazor and EF Core to build a simple stackoverflow clone. Check our part one of this series where we created our backend API. In this article we are going to get end to end working by building out our UI to get and create questions.

You can access the source code for this web app at the project github. Make sure you’re accessing the blog/initialUI tag for the code that existed at the time of writing this article.

Other TinRoll Articles

As mentioned earlier, this article is the second in a series about C# and Blazor development. Here are the links to the other articles in the series.

Blazor + EF Core: A Simple Web App Part 1

TinRoll #3: Building Out the API Layer

TinRoll #4: Creating a Generic Repository

Blazor

As explained a bit in the last article, Blazor is Microsoft’s new front end web framework launching as part of .NET Core 3. It leverages WebAssembly to provide native like performance to non-JavaScript code. Which for someone like me is refreshing because I’m not the biggest JavaScript fan.

Lets dive into the project. By default all UI code is located in the TinRoll.Client project. It’s pretty sparsely populated right now.

There’s a Program.cs and Startup.cs, which is familiar to any .NET Core project. The wwwroot folder contains css files and our index.html. You’ll see that the rest of the files in our project are razor files. These razor files are the files that allow Blazor to render our UI. They are similar to .cshtml files if you have experience using C# MVC at all.

Lets open up our MainLayout.razor file and take a look.

This is the default layout file of our app. We are defining the NavMenu, as well as injecting the page specific content with the @Body tag.

Let’s open up our FetchData.razor file to see both html and C# mixed.

At the top of the page we have the route of this particular file. As well as some C# code that will give us access to external classes. The @functions section is new. It contains one function that makes an API request to our api/SampleData/WeatherForecasts api endpoint.

Anytime we reference C# code in a .razor file we have to prefix it with an @. As you can see we aren’t showing html code until we have data, then using C# a foreach loop to display data multiple times.

Also in the functions sections, we write pretty standard C# to make an API request.

This is really the power of Blazor and WebAssembly. Where you would normallly have to leverage JavaScript you can now use C#.

In preview release 5 and earlier the @functions section was the correct way to distinguish C# code. Preview release 6 introduced the @code section, which moving forward is the recommended way to designate C# code in a razor file.

That’s a simple overview of Blazor. Microsoft has more in depth documentation on Blazor if you’re interested.

TinRoll UI

I’m going to say this at the outset, I’m not a UI expert. I spend most of my time writing backend code and most of my UI skills are out of date. The UI that I’ll be building here will be fairly basic. If you’re a UI expert you’ll probably see a lot you won’t like. I’m open to suggestions as far as my UI work goes, but I wouldn’t recommend my UI work as best practices.

Also, I’m not going to be showing the CSS used to style this app. If you’re following along and want the same styling please refer to the github project.

With that said, we are going to hook up our UI to display a list of Questions from our db. Something like this, but with data pulling from our api rather than static lorem ipsum.

To get started, lets create a razor file under our Pages folder and call it Questions.razor.

At the time of writing Visual Studio has not yet added a scaffolder for razor files. If you attempt to add a .razor file using Visual Studio you’ll get an error saying there is no scaffold provided. I had to copy and rename an existing razor file in order to get my Questions.razor page to display. I imagine this will be fixed before Blazor hits their 1.0 release.

Replace whatever is automatically generated in that file with the below code.

This is the HTML that will display our list of questions. We’re specifying the page to be located at /questions. Right now it loops and displays dummy question text five times on the screen. Lets update our NavMenu.razor file to include a link to our new razor file.

We’ve slightly modified the nav link that shipped as part of the Blazor default. We removed the Counter and FetchData links and replaced them with Questions and Tags links. If you run the app, the Questions link will display on the left nav bar. You can navigate to our dummy question page that shows a static list of questions. Now lets wire up some data.

Building out our Data Model

One of the shortcuts we took in last article was returning DbEntities directly to the UI layer. Which is a huge problem that we’re going to fix now.

Why is that a huge problem? Because you don’t want to expose everything in your data layer to your UI. What if you user table has a password? Or social security number? We don’t want those coming near the UI for security reasons. We need more control on deciding what from our database gets displayed in the UI.

For that we need to setup some kind of mapping functionality that takes our Db classes and generates DTOs to be returned to the UI. That mapping functionality will allow us to control which fields get sent to our UI. For the moment since we have no sensitive fields, our Dto and Db classes will basically be mirror images of each other. As the app progresses they will diverge when needed.

AutoMapper is a popular library used to map objects dynamically. I’ve used it in the past and lately I think the cons of AutoMapper out weigh the pros, so I’m choosing not to use it in TinRoll.

Lets create a new class in our TinRoll.Shared project called UserDto and it will contain the following three fields.

Lets do the same for our QuestionDto.

So now we have copies of our DbEntities that we want to display on the UI. Lets code some mapping functionality in our Controller layer in order to leverage it.

Controller Updates

Open up our Users controller. Our GetUsers() endpoint is returning the DbEntity User. Lets change that to our UserDto and we’ll need to also map our Users.

Comparing the old and new:

1. We’ve updated the return type

2. Saved our dbUsers to a variable

3. Created a simple Linq query to map our User object to our UserDto object

4. Returned out Dto list.

(At the moment we’re leaving off the Questions. In the future we’ll migrate this mapping code somewhere more appropriately).

We’ve updated our Controller has stopped returning Database entities! Congrats! (Still work to be done to remove data access in our Controllers, but one thing at a time)

Apply very similar changes to the QuestionsController.

Start the project up and make sure both GetQuestions and GetUsers are still working with Postman.

UI Updates

Now that both controllers aren’t returning db entities, lets actually feed data into our UI. Open up the Questions.razor page.

We are going to be copying the pattern in FetchData.razor to call the GetQuestions endpoint.

We’ll need to add the following functionality:

1. Add a function to fetch question data,

2. Replace static data with data from that api call

3. Import necessary classes

4. Ensure no errors occur before the api request returns data.

I’m using Visual Studio and the razor files seem to be having some problems with intellisense, the joys of using preview releases. so I couldn’t rely on intellisense to import items for me.

Here is our file after addressing the above functionality.

If you launch the application the question page is now replaced by data loaded from SQL.

So we now have data loaded from our database and displaying in our UI. Congrats!

New Question Form

So now we can display questions, let now add the ability to create questions from the UI. To do that I’ll need to create a new razor page that submits data to our create api.

Create a new file called CreateQuestion.razor. (Remember to copy and rename another file because of the scaffolds error.) Replace that file with the following contents.

You’ll notice that after creation we redirect the browser to the question page for this newly created question. We haven’t yet created that page, so you should receive an error trying to navigate to a page that doesn’t exist. We’ll be adding that page at the end of the article, so sit tight.

Adding Dates

So we have questions, but at the moment questions only get added at the bottom of the list. We want new questions to show up at the top. So we need to add dates columns to our database fields. Lets add a CreatedDate and UpdatedDate fields.

Since these are fields used by every one of our db entities, we’ll define these fields on an abstract class which all our data entities can inherit from. In the entities folder lets create a new class called BaseEntity. Insert the following two fields and change the type to abstract.

Then lets go into our User and Question entities and add this class as the base class. Change the class signatures to the following.

Now that we’ve added columns to our entities we’ll add a new migration. Fire up Package Manager Console, ensure the Default project is TinRoll.Data and lets add a migration called AddingDateFields by running the following command.

> Add-Migration AddingDateFields

Then lets update the database:

> Update-Database

Then lets also modified our TinRollContext class to always set both of these fields automatically everytime we save changes.

Then lets add a BaseDto class containing these two fields, then make sure our UserDto inherits from this class.

Update our controller mappings and change our database pull to order by date.

Now restart your application, create a new question and you should see your new question show up on the top of your list instead of on the bottom.

Adding a Question Page

Now we have a question list we now need to be able to see our individual question so people can provide answers. Lets add a Question page.

We need to start by adding an api endpoint to fetch a single question. Add the following method to our controller.

Then lets update our Questions.razor file to link to our individual question page. Lets update the NavLink to the following.

Then lets also add our own Question.razor page.

Now go back to your Questions and you can view individual questions.

Most of the functionality on the individual page isn’t working yet, but it’s a sign of things to come.

Congrats

We can now ask Questions, view our questions in a list, and view individual questions. There’s still a lot more features to add and better architectural practices to follow. We need to start using Blazor Components, we should separate our C# code from our razor templates, we need to start using unit tests on the backend to ensure good code quality, so many things to do. So stay tuned to see where TinRoll goes.

I’m Morgan Kenyon. I’m a .NET developer working in the DFW area. I find C# a great language to use and it’s also backed by a great ecosystem, I love solving hard problems and want to continue talking about the tech I use. If you found this article helpful or thought provoking lets connect over LinkedIn!

Github Repo

--

--

Morgan Kenyon

I’m a software developer who works with the Microsoft stack. I love to program and write about what I’m doing!