Increasing your .NET Core App's Resilience: Building a Faulting API
Tags: netcore, csharp, dotnet, showdev
Published: 2019-11-19 18:53:34

# Introduction

Imagine you're building an app that depends heavily on consuming some API that you don't own. How do you handle errors while making requests? Maybe the API couldn't respond for a couple of seconds, and now it's working again (transient errors), or maybe the service is down and no answer will be given back for a while.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/odsbvb1yhbpm090aww8c.gif)

We will be covering both scenarios on this post series, we will be simulating a faulting API that responds correctly a couple of times and then stops working for a predefined time and we will look at how to implement a retry mechanism to try sending a request again and what to do if the service does not respond after some failed intents.

# So let's start coding!
I created this sample using the .NET Core API Template from Visual Studio 2019, the "Weather Forecast".

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/i9e2doviuwppoknw9fnz.png)

Our sample uses [AspNetCoreRateLimit nuget](https://github.com/stefanprodan/AspNetCoreRateLimit) to restrict API calls by IP to simulate the "Out of service" state. You should definitely check it out, it has different ways to restrict API calls, and it's easy to get it to work.

### Once you installed the NuGet library you can add it to your __Startup.cs__

```csharp
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    // needed to load configuration from appsettings.json
    services.AddOptions();

    // needed to store rate limit counters and ip rules
    services.AddMemoryCache();

    //load general configuration from appsettings.json
    services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));

    //load ip rules from appsettings.json
    services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));

    // inject counter and rules stores
    services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
    services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();

    // https://github.com/aspnet/Hosting/issues/793
    // the IHttpContextAccessor service is not registered by default.
    // the clientId/clientIp resolvers use it.
    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

    // configuration (resolvers, counter key builders)
    services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();

    services.AddControllers();
}

```

### Don't forget to also add __app.UseIpRateLimiting();__ to your Configure Method, mine looks like this:

```csharp
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseIpRateLimiting();

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
```

### After setting up everything you can go and modify your API's appsettings.json and add the following:
*btw: don't forget to modify the __appsettings.Development.json__ as I always do*

```json
  "IpRateLimiting": {
    "EnableEndpointRateLimiting": false,
    "StackBlockedRequests": false,
    "RealIpHeader": "X-Real-IP",
    "ClientIdHeader": "X-ClientId",
    "HttpStatusCode": 500,
    "QuotaExceededMessage": "Oops, Something very bad went wrong and the server couldn't respond.",
    "GeneralRules": [
      {
        "Endpoint": "*",
        "Period": "5s",
        "Limit": 3
      }
    ]
  }
```
This will be the IpRateLimit that will be used on the services you just defined on startup.cs, it will Limit the APIs calls to 3 requests per 5 seconds only. If you receive a 4th request in between those 5 seconds, you'll get a 500 error (you can set whatever HtppStatusCode you want) and a message with a response of "Oops, Something very bad went wrong and the server couldn't respond."

Note that in *GeneralRules* you can add as many rules you want, in my case for this demo purposes I just declared that I would apply one rule to all my endpoints "Endpoint": "*", but you can create rules for one specific endpoint like "Endpoint": "get:/api/values".

That would be for our faulting API. You can now manually test the endpoint to check how it behaves.

### Now let's work on our client app that will consume the faulting API.

We will be creating a .NET Core 3.0 Worker Service that will be making requests repeatedly to our faulting API and printing on the console all the results.

For that, I started by creating a new project from the template 'Worker Service'.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/r248vfxjfxoswm2cvq0y.png)

Then at __Program.cs__ at the CreateHostBuilder method, we add the HttpClientFactory service for our API Requests.

```csharp
services.AddHttpClient<Worker>();
```
Our Program class should look like this:

```csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace NETCore_ClientConsole
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHttpClient();
                    services.AddHostedService<Worker>();
                });
    }
}
```
Now we need to edit our Worker.cs class

First, we need to create a new variable for our Client Factory

```csharp
private readonly IHttpClientFactory _clientFactory;
```

Then we can inject it to our Worker constructor like this:

```csharp
public Worker(ILogger<Worker> logger, IHttpClientFactory clientFactory)
{
    _logger = logger;
    _clientFactory = clientFactory;
}
```

Note that our Worker class inherits from BackgroundService, it will let us override some methods that we need for execution such as StartAsync, StopAsync, and ExecuteAsync.

We need to override the StartAsync method to create our Http Client, like this:

```csharp
   public override Task StartAsync(CancellationToken cancellationToken)
        {
            client = _clientFactory.CreateClient();
            return base.StartAsync(cancellationToken);
        }
```
We already defined that every time the service starts it should create our Http Client, but what if our service stops, for that, we need to override the StopAsync method, we need to tell the service that when it stops, it also Disposes our Http Client.

```csharp
public override Task StopAsync(CancellationToken cancellationToken)
        {
            client.Dispose();
            return base.StopAsync(cancellationToken);
        }
```

And finally, we implement our logic in the ExecuteAsync task, it will make repeatedly request calls delayed by 1 second to our Faulting API that we created previously __http://localhost:59316/weatherforecast__ while we don't stop the process.

If the request success, we will log a message letting us know that our API responded ok. If not, it will log a Request Failed message with the respective code status. (Remember we defined that it should be a 500 code status?)

```csharp
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                var result = await client.GetAsync("http://localhost:59316/weatherforecast");
                if (result.IsSuccessStatusCode)
                {
                    _logger.LogInformation($"Request Succeed with code status: {result.StatusCode}");
                }
                else
                {
                    _logger.LogInformation($"Request Failed with code status: {result.StatusCode}");
                }
                await Task.Delay(1000, stoppingToken);
            }
        }
```
Our final Worker class should look like this:

```csharp
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace NETCore_ClientConsole
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private readonly IHttpClientFactory _clientFactory;
        private HttpClient client;

        public Worker(ILogger<Worker> logger, IHttpClientFactory clientFactory)
        {
            _logger = logger;
            _clientFactory = clientFactory;
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            client = _clientFactory.CreateClient();
            return base.StartAsync(cancellationToken);
        }

        public override Task StopAsync(CancellationToken cancellationToken)
        {
            client.Dispose();
            return base.StopAsync(cancellationToken);
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                var result = await client.GetAsync("http://localhost:59316/weatherforecast");
                if (result.IsSuccessStatusCode)
                {
                    _logger.LogInformation($"Request Succeed with code status: {result.StatusCode}");
                }
                else
                {
                    _logger.LogInformation($"Request Failed with code status: {result.StatusCode}");
                }
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

```
We did it! now you can run our Worker Service by hitting F5! 
*psst! don't forget to [set up both projects](https://docs.microsoft.com/en-us/visualstudio/ide/how-to-set-multiple-startup-projects?view=vs-2019), the API and the Service.*

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/psw3goi6ecn53x8f8392.gif)


#Summary

That's all for now! you already learned to create a Faulting API by restricting incoming API calls and responding with different HTTP responses.
Also, we created a Worker Service client to consume our API and see how it behaves after several API calls.

I hope you enjoyed this as much as me while writing this. 
In the next chapter I'll be adding different Resilience patterns to our client like Retry and Circuit Breaker, so Subscribe!

You can find the full working sample at GitHub ❤

{% github maurocon3ras/NETCore-FaultingAPI %}