Using .Net Core Worker Services in a Dotvvm Web Application

Vincent Nwonah
Sep 20 · 8 min read
Image for post
Image for post
Weather Information for Lagos Screenshot

Introduction

.Net Core Worker Services was shipped as part of .Net Core 3.0. It is a new type of application template that allows you build long running services in .Net Core.

Although you can create and host .Net Core Applications that are just worker services, i.e that is all there is to the application, a couple of non-user interruptible process that just run and perform an action over and over again depending on the constraints you give to it, you can also create asp.net core and DOTVVM web applications that have a standard web pages for users to navigate to, and still have worker services running in the background in your worker service.

Why would you want this? Imagine you have to build an application that displays current currency conversion rates on your home page. For you to get the current rates, you have to call an external API which more often than not, has a rate limit. It becomes impractical to make a call to this API every time a user navigates to your application. If your site gains some popularity, we are talking thousands/millions of calls to the external API every minute, or even seconds as people browse to your site. How can be solve this with Worker Services?

With Worker Services, we can remodel our application. Instead of calling the external API to get current currency conversion rates each time a user navigates to our web page, we can build a worker service to run on the background, say every 1 minute, get the conversion rates, and caches them. This way, even if a million users navigate to our application at a time, we call the API just once per minute, staying well within rate limits. Some people may argue that cached results from a minute ago isn’t exactly current, if this is a bother, the worker service can be modified to call and cache results every second. This would still be much better than say all your 200 requests/second by users call the API 200 times a second.

Now that we understand why to use worker services in a Web Application, let us talk about the “how”.

What we will be Building

We will be building a simple application that displays weather information for a city, for this application I am picking my current city, Lagos, Nigeria. We will retrieve current weather information for Lagos, Nigeria from the Open Weather Maps API at https://rapidapi.com/community/api/open-weather-map. This API has a rate limit of 10 requests/minute so it’s perfect for the scenario described above. We will get the weather info for our city every 30 minutes and cache it, when users navigate to our site, we will display the cached results. We can also increase the frequency for higher accuracy but since this is for educational purposes, we can leave it at 30 minutes.

Getting an API Key for the Open Weather Map API

The first thing we need to do is acquire an API Key that allows us make requests to the Open Weather Maps API. To get a key, navigate to https://rapidapi.com/community/api/open-weather-map and acquire a key, you can test some of the endpoints directly from the browser, copy and save this key.

Creating the Project

I will be using a Dotvvm Web Application Template, if you are unfamiliar with Dotvvm, I wrote an article here https://medium.com/dotvvm/setting-up-for-dotvvm-development-on-linux-macos-and-windows-ddda46a57380 that briefly highlights what Dotvvm Applications are, and why you might want to use them. For a more in-depth look at the MVVM Framework, head over to https://dotvvm.com. Nevertheless, feel free to follow along with a regular asp.net core MVC or razor pages web application.

Open up Visual Studio and create a new Dotvvm Project, I am naming mine “DotvvmWorkerServices”, we will not be adding authentication or crud pages, be sure to add bootstrap4 as we will be using it to style our application.

Adding a Http Client to Call the Weather API

The next thing we need to do is create a Weather Response class to receive the deserialized response JSON from a successful API call, and a Service class to make this call. Because I already know the structure of the JSON, I am adding the class definition below. You can call the API from the website, get the JSON, and use a tool like https://quicktype.io/csharp/ to generate your class def.

Create a Models folder if it doesn’t already exist, and add a class called WeatherInfo. Add the class definition below to the file, remember to change the namespace if you named your project differently from mine.

To create the Service class for the API calls, create a “Services” folder and add a class named WeatherInfoService to this class, add the code below to the class.

What does this class do? Notice that we are Injecting a HttpClient into the constructor and saving it into a readonly field, we use this HttpClient to make a request against the /weather endpoint of the API passing in the units parameter as metric, and setting the q parameter to the city, country for which we want weather details, this can be passed into the GetWeatherData method. The method makes the resquest, deserializes the response and returns a WeatherInfo object to the caller.

You may be wondering where we set the baseurl for the HttpClient, or the request headers, authorization key, etc. We are using using a .Net Core 3.1 feature called Typed Http Clients, that allow us define and configure HttpClients in the Startup.cs file, making them available to be injected into any class that needs them.

Open up the Startup.cs file and add the following lines of code to the ConfigureServices method.

In these lines of code, we are registering a typed Http Client and setting the base address and default request headers. With this done, asp.net core’s DI will supply a ready to use client to our WeatherInfoService class whenever it needs one. To learn more about the new Http Client types introduced in .Net Core 3.1 see the official Microsoft documentation.

At this point our service class is ready to use.

Adding the Worker Services

Start with adding an AppConfig.cs class at the root of your project and add the code below to it.

We will use the WEATHER_INFOS_KEY to cache values within the background service.

Next, create a folder at the root of the project called “Background Services” and add a class named GetWeatherInfoBackgroundService to the class. Add the code below to the class.

In the preceding code, we create a class GetWeatherInforBackgroundService which inherits from the .Net Core’s BackgroundService class. All background services have to inherit this class, and implement the ExecuteAsync method.

We are injecting an IMemoryCache and our WeatherInfoService into the constructor, and saving them into private fields. If you’re wondering where the IMemoryCache class comes from, it is supplied by default with asp.net core and can be a quick, cheap and effective way to do caching in simple web applications. You can find my article on the IMemoryCache on my blog or check the official Microsoft documentation here.

Within the ExecuteAsync method, we start by caching a list of strings with their key being the Key we defined in the AppConfig.cs class. Because we want to restrict the number of weather results available in the cache at any given time, we use this list to ensure the number is never over 10.

Next, we have a pseudo-infinite loop that only stop’s running if we ask it to, this behavior is achieved by creating a while loop and setting its stop condition to !stoppingToken.IsCancellationRequested, this behavior is available to our service via the inherited Background Service class.

Within the loop, we start by calling getting the current weather information by calling the API via our service class. For this call we pass in the city and country for which we want weather info for. The next 6 lines of code gets all the current weather info in the cache, and checks if they are over 10, removing the oldest result if the check returns true.

We proceed to adding the Date in UNIX Timestamp value that is part of the weather info we just got from the API to the values collection, persist this to cache, then persist the entire weather info response object to cache using its UNIX Timestamp as key.

On the next line, we set a delay for 1 minute, this will pause the background service for an entire minute, after which it will call the API, get a new weather info process it, and wait again, this process continues indefinitely, every minute. But how do we tell asp.net core to run our background service?

Open up Startup.cs and add the line of code services.AddHostedService<GetWeatherInfoBackgroundService>(); to the ConfigureServices method. Now asp.net core knows to run the service once the project starts.

Modifying the DefaultViewModel Class

The final bit of our application is the display part, since I am using DOTVVM this is the easiest part. We need a DTO class to feed information to our view.

In the Models folder, add a WeatherInfoDto class and add the code below to it.

Next, expand the ViewModels folder, open the DefaultViewModel class and replace the code in it with the one below.

Let us walkthrough what this code does; first we are injecting our IMemoryCache so we can get our cached weather info. Next, we create and instantiate a List of WeatherInfoDto which holds the data we are feeding to the view.

In the PreRender method we start by creating a list of WeatherInfoModels to store the info retrieved from our cache. We then proceed to get the keys for each weather info in our cache using the values the keys variable in the first foreach loop, adding them to the Lisr of Weather Information Models as we do.

We use a second foreach loop to transform the models to a WeatherInfoDto, and add them to our list of Dtos. We can do this using some LINQ, or AutoMapper, I have done it verbosely here for code clarity. At this point we are ready to display some weather information in the browser!

Modifying the Default.dothtml View

The last bit of functionality is adding the required markup to display or list of weather info to the user. Using DOTVVM again makes this much easier. Simply open up the Default.dothtml file in the Views folder and add the markup code below to it.

If you run the project and wait awhile, you should see the weather information start to show up like the screenshot above.

If you’re wondering how this HTML Markup works, it’s a little magic called Model Binding provided with DOTVVM. The line of interest is <dot:GridView DataSource=”{value: WeatherInfos}” class=”table”>. Notice how we are setting a DataSource property to the WeatherInfos property we created in the ViewModel? This is DOTVVM’s model binding in action.

Conclusion

In this article we have seen how to use .Net Core’s new Worker Services in a web application, we have also touched on other concepts like typed Http Clients, IMemoryCache, etc.

The demo full source code for this project is open on github, and you can run the live site here. Feel free to reach out to me via email: vnwonah [at] outlook.com for help/recommendations, correction.

Vincent Nwonah

Written by

Software Developer

DotVVM

DotVVM

DotVVM is an open source ASP.NET framework that lets you build line-of-business applications and SPAs without writing tons of JavaScript code.

Vincent Nwonah

Written by

Software Developer

DotVVM

DotVVM

DotVVM is an open source ASP.NET framework that lets you build line-of-business applications and SPAs without writing tons of JavaScript code.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store