Blazor Weather Forecast CRUD

 


On my way to set up SQLite within Blazor, I ran into a few more hurdles than I was expecting. So, I decided to write about it. I have used SQLite with C# in the past and it was quite straightforward. But since then, there must have been a couple of updates that did not work quite like they expected.

Once I got SQLite working, I decided it would be fun to create a new Weather Forecast CRUD application to highlight using SQLite with Blazor. That part turned out to be fun.

Application Goal

The goal was simple, using the Weather Forecast, Fetch data, part of the standard Blazor template, read the records from an SQLite database, and add the functionality of adding, editing, and deleting forecast records. Additionally, I wanted to use TailwindCss for styling. I am incredibly pleased with the result of the application.


Connecting to SQLite

Connection to SQLite has simple steps:

    1. Add NuGet Microsoft.EntityFramework.Core.SQLite
    2. Add NuGet Microsoft.EntityFramework.Core.Tools
    3. Create the db context
    4. Add the DbContext Service in Program.cs

        builder.Services.AddDbContext<WeatherDbContext>(options =>
        {
            options.UseSqlite("Data Source = data\\WeatherData.db");
        });

    5. Run the DB migrations to initial the database.

    Normally that is all that is needed, but when I tried to run the DB migrations I received an error:
 
"You need to call SQLitePCL.raw.SetProvider()" error when using Microsoft.EntityFrameworkCore.Sqlite 5.0.4 via C++\CLI wrapper”
After getting frustrated and googling, I found the solution(https://github.com/dotnet/efcore/issues/24493). There is a NuGet package called SQLitePCLRaw.batteries_v2.dll. 

Once I added this NuGet package I was able to run the db migrations and create the SQLite database. The article really did not say what the issue was but adding the NuGet package did work. 

I did add a method to do the initial population of the database with ten records. It helps when building out the other pages.

Weather Forecast Service

I expanded the Weather Forecast service to be a repository for the WeatherForecast db set. I added the following methods:

    1. Constructor that injects the WeatherDBContext
    2. Populate Data Base
        a. This is only called if the database has no Weather Forecast items
    3. GetAsync
        a. This method returns the collection of records from the database.
    4. Add Forecast
    5. Update Forecast
    6. Delete Forecast

I could have just used an UpInsert method to manage both the add and the update. I personally prefer separate Add and Update for simplicity.

Data Grid View

I had to add additional functionality to the grid on the FetchData page. I added the ability to:

    1. Load the grid from the GetAsync method from the Weather Forecast service
    2. Click on a grid item
        a. Have the grid highlighted
        b. Store the current grid item that was clicked on.
            i. We will need this for the delete and the edit.
I added three action buttons right above the grid. The user will use these buttons to Add, Edit and 
Delete records.



Using the click on grid item event, I was able to disable the Edit and Delete buttons if there were no records selected.

The code that manages the highlighting of the grid line that was clicked on is done via JavaScript. When a row is clicked, we must turn off any highlighted rows and then highlight the one row that was clicked. At some point, I would like to see if this can be done in C#.


Add / Edit Form




The date is set to the current date. The standard HTML input with a type of date is used for the data input. I found it easy to work with. The standard HTML input with the type of number is used for the temperature. The summary is just a text input.


On cancel, I just return to the grid page. 

On Save, the application will:

    1. Validate the data entered, date, temperature and summary are not empty
    2. Call the Weather Forecast service to save the record
    3. The application will return to the fetch data page and display either a successful or error message

For editing, I use the forecast object in the application state and populate the form:


Cancel and Save work the same as add, but will update the record, instead of adding it.

Delete Confirmation Modal

For the delete function, I need to prompt the user for confirmation that they really want to delete the selected record. If so, we will delete it from the database. When the record is successfully deleted, we need to re-load the forecast items from the database and refresh the grid. We need to close the modal and clean up the row selection index.

There are several good NuGet packages I could have used for the confirmation modal, but I created my own and it looks sharp.





It was easy to support the modal once it was created. I made the “hidden” class soft. When the user clicks on the “Delete” button, the modal is displayed. If the user clicks on the ”No, cancel” button, the hidden class is reset, and the UI is updated. If the user clicks on the “Yes, I’m sure” button, the delete forecast method in the WeatherForecast service is called.

On success, the success message is displayed. If there is an error deleting the record, the error message is displayed. The last step is to reset the hidden class and close the modal. The date and summary on the modal are displayed so the user can see which forecast they are deleting.

An additional project that I might do is to create a reusable component out of this modal because it looks so cool.


Toast

At first, I thought I would just create the toast like the model, but it was more work than I wanted to do. I went with the Blazored Toast (https://github.com/Blazored/Toast) NuGet and is easy to use, even though it does have a Bootstrap look to it. I might look at creating my own with TailwindCss styling.


Application State

I went with using Application State to pass the forecast object to the edit page. I did this as opposed to passing the ID and then retrieving the record from the database. Using the application state saves a db lookup.

This application is built as a Blazor Serve application. Application State service must be defined as a Scoped Service. This will ensure the data is per session. If you define it as a Singleton, the data is shared between all users. If this were a Web Assembly application, you would use a Singleton since it is running on the client side.

    builder.Services.AddScoped<AppDataService>(); 

The service, itself contains several properties, a property for a Weather Forecast object, a property for the Result from adding / editing, and a property for any errors from adding / editing.

 

Styling

Keeping with my current philosophy I am still restyling using my blog applications with TailwindCss(https://tailwindcss.com). It makes things so much easier to style. For some reason, TailwindCss has just clicked with me.

 

Summary

This was a fun and educational project. The main goal of getting SQLite to work within Blazor took extra steps, but I got it working. The styling, modal, and grid events added real enjoyment to the project.

I will continue to use/add to this project for other blog posts.

 

[source]




Comments

Popular posts from this blog

Yes, Blazor Server can scale!

Blazor new and improved Search Box

Blazor Wizard Step Component