In this episode, we’ll start building our backend for frontend, which will bridge the interaction between the Vue.js frontend application and the backend APIs we’ll develop. For now this will be mostly an excuse for playing with the
HttpClient in ASP.NET Core, as we’ll improve the BFF in the future, with some proxying capabilities for requests that don’t need additional logic.
For the walk-through you can check out the next video, but if you prefer a quick read, skip to the written synthesis.
The playlist for the whole series is here.
In this episode, we’ll start building our backend for frontend, which will bridge the interaction between the Vue.js frontend application and the backend APIs we’ll develop.
A backend for frontend (to which we’ll refer to as BFF) isn’t a required piece, but can be a useful one when we’re working with an application which is composed by multiple services, as is our goal with the PlayBall application.
The main goal of having a BFF is to create a simpler interface between a frontend and the backend. During this project, the Vue.js application will mostly likely be the only frontend we’ll develop, but imagining that we would have more options (Android, iPhone, smart watches, TVs, …), a BFF would allow us to create a tailored API for the specific frontend, simplifying the work in the client’s device, having it done instead in the server, closer to the supporting services.
In this episode, we’ll basically just create the project and use it as an excuse to play around with the
HttpClient in ASP.NET Core, to see some relevant usage patterns that emerged recently. In the future we’ll improve the BFF, so simple calls to the services can be proxied automatically, allowing us to only write code when we want to tailor the API to the frontend.
To improve the BFF in the future, we’ll explore ProxyKit and Ocelot (or other projects that show up until then), but that’s a subject for another time 🙂.
As the backend for frontend is specific to a… frontend (🙃), we’ll put it next to the Vue.js application, in the same GitHub repository.
It will be an ASP.NET Core 2.2 application, like the GroupManagement service we developed in past episodes. In the repo, we’ll have the following structure:
. ├── client | ├── Vue.js application files | └── ... ├── server | ├── src | | └── CodingMilitia.PlayBall.WebFrontend.BackForFront.Web | | ├── CodingMilitia.PlayBall.WebFrontend.BackForFront.Web.csproj | | ├── BFF application files | | └── ... | ├── CodingMilitia.PlayBall.WebFrontend.BackForFront.sln | └── .gitignore ├── LICENSE └── README
Before starting the with the main objective of this episode (playing with the
HttpClient), let’s do some initial setup. Beginning with the
Startup class, we want to get MVC working, as we’ll implement the “proxying” logic in controllers. We already saw this in the past, but as a refresher:
Regarding the organization of the application, this time instead of the “classic”
Views folders, we’ll create a
Features folder, and split things by feature in there. Right now the
GroupManagement service only has groups logic, so the BFF will only have a
Groups folder, with a
GroupsController and a
GroupModel. We’ll see the controller in a bit, but regarding the
GroupModel, it’s an exact copy of the one in the group management service.
Implementing the requests
Let’s take a look at our
GroupsController implementation to see how we fullfil the requests. It’s really boiler plate code, that’s why we’ll try to get rid of it in a later episode, but I think it’s worth the quick look.
Just before diving into the code, a couple of notes:
- We’ll get the
HttpClientas a parameter in the constructor, we’ll see how to configure it in a moment. The
HttpClientcomes with the base address of the group management service pre-configured.
- We won’t worry about handling errors right now, but we definitely have to do it in the future.
Let’s start with the action to get all groups.
The first thing I’d like to point out, is the return type of the
GetAllAsync method, as it’s something I haven’t used yet in this series. Normally when implementing an API action method, we would indicate as the return type the model we’ll return, or if we need to return a different status code (like a 500, 404, etc) we would declare it as an
ActionResult<T> is an interesting little class that allows us to have the best of both worlds. If we to return a
NotFound(), it’ll work fine, if we want to return a model directly, it’ll also work fine. That’s because it has implicit operators to make those conversions. The corner case is exactly the one you see above. The implicit operators don’t work with interfaces, hence the
return Ok(result). If, for example, I had used
GroupModel instead, it would have worked just fine.
Regarding the HTTP request, nothing too strange going on I think. We make a GET request with the base address, as we want to list the available groups, then read the JSON response so we can return it. The models are an exact match, so no need for any mapping logic.
Onwards to the get by id action.
Again, more of the same. We do some extra url composition before making the request, then we check if we got a 404 so we propagate that status if needed, otherwise we parse the response and return it, as you can see, taking advantage of the implicit conversion of the model.
The rest of the actions are more of the same, so I’ll just drop them here for reference.
Using the HttpClient (before ASP.NET Core 2.1)
Before looking at how we’ll use the
HttpClient, let’s take a quick aside to talk about how it was normally used prior to ASP.NET Core 2.1.
I’ve mentioned this in a past post, but using the
HttpClient isn’t as straightforward as one would expect in the first place.
HttpClient implements the
IDisposable interface, so it’s easy to assume that the best way to use it is just wrap it in a
using block, making the required requests in there, having it disposed afterwards. Unfortunately, this isn’t the best way, as even when we dispose of it, the socket it used to make the requests isn’t let go immediately, it remains open for a while. This may not have an impact on a not too loaded application, but if there is sufficient load, we can start to see port exhaustion due to this behavior (more info here).
Knowing this, what’s the solution? Well, just create a single
HttpClient and share it (or a constrained number of instances at least). The methods used to make the requests (
PostAsync and so on) are thread safe, so no problem there, as long as we’re careful with the other stuff (e.g. messing with
DefaultRequestHeaders). It isn’t ideal, but knowing the issues, we can go around the problem right?
When it seems we’ve found a good’ish solution, another problem bites us! If we keep the client for the lifetime of the application, eventual DNS changes are not detected (more info here)! Again, we find another solution by playing around with the
ServicePointManager and we’re good to go (again, go here for more details).
But these are a lot of weird hoops to go through, and there are probably other issues I don’t even know. Fortunately, with ASP.NET Core 2.1, a new set of features emerged to ease this pain, mainly the new
Using the HttpClient
We have the controller ready to make the requests, and we’ve seen some of the problems we faced with the
HttpClient in the past, so now it’s time to see how to use it in ASP.NET Core >= 2.1.
In this post I’m not going in a lot of details about the new
HttpClientFactoryusage patterns, I’ll just use them to implement what we need in our application, but for a more detailed read, Steve Gordon has a great series of posts you can check out, starting with this one.
As I briefly mentioned, there is a new type called
HttpClientFactory, which like the name suggests, provides us with instances of the
HttpClient. The problems mentioned earlier about the
HttpClient don’t stem from it directly, but from the
HttpClientHandler it uses internally to actually make the requests. With the new features, this handlers are pooled and used by the
HttpClients, so we don’t really need to worry about disposing the clients (again, for a much more detailed explanation, check this post out).
We can inject the factory directly into the classes that need to make requests, or we can configure the class as I typed client, getting the
HttpClient in the constructor immediately without needing the factory. In this case, we’ll go with the typed client, but of course there may be cases where the factory is preferred.
Startup class, we’ll add the configuration for the typed client.
Even though this code is only setting the base address, we can configure various aspects of the client. We could also delegate these configurations to the actual class that’ll be using, I’d say it’s a matter of preference, or maybe in some situations one makes more sense than the other.
This should be it to have the thing running, but it’s not, because we aren’t injecting the
HttpClient into a “normal” class, we’re injecting it into a controller. Controllers aren’t registered into the dependency injection container as services, like the other classes we registered, so if we try to run the application like this and make a request to
http://localhost:5000/groups, we’ll get an error like:
An unhandled exception occurred while processing the request. InvalidOperationException: Unable to resolve service for type 'System.Net.Http.HttpClient' while attempting to activate 'CodingMilitia.PlayBall.WebFrontend.BackForFront.Web.Features.Groups.GroupsController'.
To be able to make use of the typed client with the controller, we need to go back to MVC configuration in
ConfigureServices and add an extra line to register the controllers as services, so all of this can wire up nicely.
There are other similar methods, like
AddTagHelpersAsServices, but we only need controllers right now.
Now we can test again and everything should work as expected.
Using Polly to add retry logic
The final thing we’ll take a quick look in this post is using Polly to have the
HttpClient retry upon a failed request.
I have a an older post (here) and video (here) about Polly in general. In this post we’ll just take a quick look at the more recently added integration between Polly and the HttpClient in ASP.NET Core. Polly has a lot more feature than just the retries we’ll briefly look at in this post.
To have the Polly
HttpClient integration, we need to install the
Microsoft.Extensions.Http.Polly NuGet package. Then with a couple of lines of code added to the
Startup class, we have everything ready.
AddPolicyHandler is an extension method from the NuGet package we installed. It allows us to configure policies to apply to the
HttpClient. Policies are a Polly concept, and are something in which we can wrap an action execution, adding some additional behavior to it, namely implementing some resilience patterns. Some examples of policies are retries, circuit-breakers or timeouts.
In the above code we’re configuring a retry policy for transient HTTP errors - from the docs: in the 500 range (server errors) and 408 (request timeout). We have a bunch of options for configuring retries, like retrying immediately, retrying after some time, always retrying on error, retrying for a number of times, and some more variations of these.
The approach taken here is to wait after each failure before retrying, for a maximum of 5 retries. Each time the request fails, the retry is attempted the number of the retry seconds later, or to be clearer, the first retry will wait for 1 second and the last one will wait for 5 seconds.
To see this in action, we can go to the group management service and mess with the code a bit, adding some random exceptions and stuff 🙂.
That does it for this first look at the backend for frontend, or better yet, an excuse to use the
HttpClient 😛. If you think what we implemented here is a bit silly, well… it probably is, as we have tools to do this kind of proxying for us, without writing loads of boiler plate code. As mentioned, we’ll tackle that subject in the future, but for now I thought it would be relevant to point out the new usage patterns of the
HttpClient, alerting again for the troubles that using it incorrectly may bring.
Also, we could bypass the backend for frontend altogether and leave to the frontend the responsibility of calling all the required services. I think however, that this will give us some more flexibility in the future, particularly for things like authentication and authorization (as we’ll see in the next episode) or if we have interactions with services that don’t expose an HTTP API (for instance, I’m pretty sure we will play a bit with gRPC at some point).
Links in the post:
- You’re using HttpClient wrong and it is destabilizing your software
- Singleton HttpClient? Beware of this serious behaviour and how to fix it
- HttpClientFactory in ASP.NET Core 2.1
- Simpler error handling in .NET applications using Polly
The source code for this post is here.
Sharing and feedback always appreciated!
Thanks for stopping by, cyaz!