Blazor WebAssembly — Part II: Calling an external API

Claudio Santos
10 min readJan 22, 2022

This story is part of a series!

Blazor WebAssembly — Part I: Installing and preparation with MudBlazor | by Claudio Santos | Jan, 2022 | Medium

Part II —Blazor WebAssembly: Calling an external API (This article)

So, we have powered up the Blazor WebAssembly APP! YAY!

WE DID IT! Well, it was just the start, but anyway…CELEBRATION!!

As I´ve told you, I want to make a kind of portal, and I thought:

It would be nice to have like a location and weather forecast in my homepage, people always like that!

So, I´ve researched a little bit on the web, and I wanted one API that had an OpenApi standard so I could test auto-generated code into the Blazor app, but I didn´t find any that would make it as I wanted, but I found the famous Accuweather.com one, it´s “kind of” free (50 requests per day), so I created an account there, created an app on their developer portal (https://developer.accuweather.com/) and I got my private key!

The API had multiple endpoints that I would really not need, but I saw two that got my attention:

  • IP Adress search: Returns information about a specific location, by IP Address.
  • 1 Day of Daily Forecasts: returns a forecast based on a location key that we have to have beforehand.

We could get a location in multiple ways, but the part on IP address got my attention as I was very curious about how to get the IP address in a Blazor app!

So let´s go!

Creating the service plugin project

Well creating the API request should not be rocket science, so let´s start here.

As I want to re-use as much as possible for future multiplatform solutions, I want to separate all external services into their project class context, so I will create Plugins.External.Weather project to have this encapsulated.

Inside this Project, I created also the following folder structure for starters:

  • Contracts (we want to use interfaces!!!)
  • Exceptions (I like to have my custom exceptions created and useful)
  • Implementation (Here is where the magic is done)
  • Models (For sure we will have to pass data inside the requests and we will receive data that should also be organized!)

Heading to the AccuWeather site, I went to the page for the Location via IP, and saw that we need 4 parameters: ApiKey, Ip, Language, and Details. Also, each request they had in the API documentation was slightly different, and I really wanted just to use 2 of them, so decided to create the following AccuWeatherConfigurationOptions Model (in this article I will only cover the Location part)

And also I saw the example answer… It was huge! I didn´t need all this information! But, I want to show you a trick if you need all the information and we don´t have an open API Standard (with the auto-generated code), and, like me, don´t like to create enormous Models by hand.

First, get a complete sample response, copy it, and then go to the website https://json2csharp.com/ and paste the JSON code… you will have the C# models created on the right side hihihihiih! You just have to pay attention to some int cases that are in reality double cases, the rest normally goes ok!

Time is money, my friend!

I adjusted a little bit the result of the conversion to C#, and added all the “root” properties to a class called AccuWeatherLocationResponse.cs (again, I don´t need all this information, was just to show this trick, in my production development, I will create a much smaller class to hold just the properties that I need), and so I have my initial models done. After the models, I create the WeatherServiceException ! All these are simple classes and you can see them in the GitHub Repository for this part =>

Now let's create the service and its interface, again, in this article I will only cover the Location part, so our service should be a simple one method Get Request, and we should have in the constructor the HttpClient injected and also the configuration options injected. It will be something like this:

Notice that I have installed Newtonsoft … =)

So, after this, normally I will go to AppSettings and create the settings that in this case, the web service will need ( the apikey and the destination URL ), but… WHERE IS APPSETTINGS.JSON???

WHYYYY … Where is appSettings.json????

So, it seems, that Microsoft, for Blazor Web Assembly apps, have removed the appsettings.json, but we can add it, the issue is… as in the case of Blazor Web Assembly apps, the client downloads all the files, and it “runs” mostly in the client-side, you have to add your appsettings.json file to the wwwroot folder and IT WILL BE DOWNLOADED TO THE CLIENT. So, I cannot write secrets there! It would be insane! Well for the purpose of this tutorial, I will add the appsettings.json but, FOR SURE, in the solution that I´m creating for production, I will insert all the secrets in AZURE KEYVAULT (it will be even more profitable because again, I want to go multi-platform, and so, having the secrets and settings centralized, it would be easy and maintains consistency)

Damn…the client would see all my keys!

Of course, I can still use it and make all the keys/values in the appsettings.json encrypted and code some encrypt and decrypt strategy to handle it… but again… it does not sound well! =(

How to add the appsettings.json? Well first create one manually in the wwwroot folder.

Creating an appsettings.json

Then we have to add the loading of the file in startup.cs …. Program.cs I mean =)

The best way is to create a method to do it because I am thinking that it will be very easy to “pollute” program.cs, so create a static method that will do the loading of the file and add it to the configuration.

And then we just have to call this method inside the program.cs, and bring it to the top as possible, in my case, the program.cs ended up like this! (line 10)

Ufff now we have appsettings.json back (but, to be honest, I really will change to KeyVault, this seems so bad…)

Now, all it remains to be done considering the weather service is to add it to the available services and inject the needed data. This needs to be added to Program.cs, after the Core Services but before the Build() of course:

Adding a new project for storing Use Cases

As I´ve told you before, I will try to use a Use Case approach on this development, so the first thing to do is create a new project inside the solution, a class library, for the Use Cases, then, and considering that my use case will be the data for the landing page, as I want to provide the users a lot of different data in the landing page. I might have to add new use cases for mobile after, but for the moment, I will do the desktop main page data use case:

After creating the library, we have to add our first use case, we will call it MainPageDataUseCase.cs , and at the moment, our execute method only needs the IP of the user, so it can pass to the service we will create and get the location. I say at the moment, because we will probably need more data from the initial loaded user or others in the future, and at that time we will add data. As we are preparing already for receiving more data, it´s easier to add right now a simple class to handle this.

Create a folder for Interfaces, a folder for PagesUseCases, and a folder for RequestModels, and inside RequestModels, create a class named MainPageRequestModel

In the end, the MainPageDataUseCase will do all the work or orchestrate the needed things to get the needed data or make the needed transformations for that use case. In my case, it got this shape at the moment:

Also, we have to add all these services to our DI, so let´s go to Program.cs ( I got it right now! no more startup.cs) and add them to the Services:

FINALLY to Blazor!!!!!

We finally will make our first code change in a razor file! We will show the IP and the place where the user is, and we will use some MudBlazor components to do it!

So, this weather/location will be a control, so we can re-use it on more pages if needed, and so, we should create a folder to hold our controls, and inside we will create our WeatherInformation.razor component.

Something like this… I am really bad giving names…sorry

In this new file, at the bottom, we will find our code directive, and you guess it right, it is here that we insert our C# frontend code! Crazy times we live! =)

First, as we will receive the model from the API response, we have to add a couple of namespaces to the _imports.razor, but for that, we have to add the references of the libraries we have created to the main Blazor project, add simple references to them, and then in the _imports.razor file add:

Blazor works based on life cycle events, just like for example Angular, and so, inside that Code block, you can Override (type override and next press tab to see all possible override methods) much of the events, and in this case, we want to override the OnInitializedAsync event. Inside this Life Cycle event, we will grab the user Ip and send it to our UseCase and it will ask the web service and return, for now, the location.

As a normal C# file, you can just code something like this

But… HOW DO I GET THE USER IP IN BLAZOR WEB ASSEMBLY? We all know how to do this on the server, we can use the request… but, we are in the client!!! How can we do this? I have researched the Web a lot, and the best way is to make a call to https://jsonip.com/ and get the IP… Again, this sucks! I don't want to do this, but I cannot find another solution… Hey Microsoft, please give us this =)

We will need to make a call outside, and maybe it's easier using Javascript (we could use other ways, but I want to show how to call Javascript from the C# code) also in the future, we will create separate JS files and make this a really hybrid solution, but for now, head to wwwroot/index.html and add a script tag at the end with the following code:

After this, go back to our new razor component, and on top, add the inject for the JavaScript runtime

Yes! Inject directly into everywhere!!!!

Now we can use the JavaScript Runtime to call the Javascript function and we can work the result out!

The Code block should now look something like this:

Uffff we should have sorted out all that we need to call the web service now let's present something to the users!

As I´ve said, MudBlazor will be our choice! And it also has a Grid System, just like Bootstrap ( https://mudblazor.com/components/grid#grid-with-breakpoints ) the MudGrid that have MudItems inside, and then we can use a MudCard!

Ok! Let's go for them all! The card is a simple implementation, very similar to bootstrap ( https://mudblazor.com/components/card#outlined ) and you can see that we use properties in the tags to set the data. The combinations are so wild that I recommend that you check the documentation for the look and feel you need! In simple, MudPapper is like a box, a wrapper, MudText is text, MudCard creates cards, and so on! You can really find it similar to other UI frameworks!

I will do a simple card with the information, no need to fuzz anymore and it will be something like this:

As you can see, we are using the Mud directives as we would use XML or HTML and we add content. Please note that whenever we want to use variables from our C# code block we start with an @ ! If you want, and sometimes you will need, you can add brackets after the @ so you can define more clearly the block like @( some code here ) ! Also note that I have that null verification in response, that is major important because if you access a null pointer on initialization, the system will throw an exception! And the funny thing is, as we are at the client if you go to your browser developer tools (F12) you can see the exception “ at C# style”!

In the final step, we have to use this control on our main page, so head to index.razor and add a call to our newly formed controller, like this:

And that's it! Fire up the system and check the result

Weeee made it!!!

Considerations

Hum somethings I have to adapt, the appsettings.json file, I think its one of the priorities to add a key vault or another system to manage the app settings, also I need to add Data storage and I am considering adding my own API in the middle, as well, for example of the weather, if I only have 50 calls to the API, I might want to store the results of it and do some magic if possible to avoid multiple calls, and if I go multiplatform, I would have to have an API to support this for me, so probably next article will be adding an API to this Blazor Web Assembly approach, but until now, we are on!

Thanks for reading.

--

--

Claudio Santos

A tech-savvy, .net developer, regular crazy guy! C#, Xamarin, Unity, AR/VR/MR, Azure, Angular... But also concerned about the planet and people!