How to Turn Off Console Logging for Kestrel in .NET Core

This post is mostly a note to myself.

I am often annoyed with the amount of logging to the console that occurs when I start a Kestrel hosted application and I can never remember how to turn it off.

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
    .ConfigureLogging(loggingBuilder => 
        loggingBuilder.AddFilter<ConsoleLoggerProvider>(level => 
            level == LogLevel.None))
        .UseStartup<Startup>();

Dynamically Updating the Request Header of a HttpClientFactory Generated HttpClient, Part 1

Full source code here.

There are some subtle issues in the way I use DI in this post, see here for an alternative if you don’t want to follow this approach

While using the HttpClientFactory I hit a scenario where I needed to update the value of a token passed in the header of requests, the token changed frequently, so I had to repeatedly update it throughout the lifetime of my application.

You have a couple of options for this, the first is to do it after you have taken a HttpClient from the factory at the point where you make your outbound request, this is straightforward, but now everywhere use a HttpClient you have to be able to get a new token. For some this might be fine, and you can use –

    httpClient.DefaultRequestHeaders.Add("Token", _tokenGenerator.GetToken());

Doing it with HttpClientFactory
The better approach is to put all this logic in the Startup.cs and update the header when the factory returns a new HttpClient, now everywhere you use the HttpClient gets the updated token without any work for you.

In my example case I have a token generator and memory cache. If there is a token in the cache, that one is used, if not the token generator generates and stores the new token in the cache for specified period.

In my Startup.cs all I need is this –

services.AddHttpClient("RemoteServer", client =>
{
    client.BaseAddress = new Uri("http://localhost:5000/api/");
    client.DefaultRequestHeaders.Add("Accept", "application/json");
    client.DefaultRequestHeaders.Add("Token", TokenGenerator.GetToken());
});

Read on to see how to wire everything up.

A little known feature of .NET Core is the ability to DI from Program.cs into Startup.cs, I have written about this before in Using Dependency Injection with Startup.cs in ASP.NET Core and am using it again here.

In Program.cs I add a memory cache and a token generator to the service collection.

Adding to the service collection this way can have some unexpected side effects, check this post for an alternative approach.

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
    .ConfigureServices(cs => cs.AddMemoryCache())
    .ConfigureServices(cs => cs.AddSingleton<ITokenGenerator, TokenGenerator>())
        .UseStartup<Startup>();

In Startup.cs I pass a ITokenGenerator to the constructor.

public Startup(IConfiguration configuration, ITokenGenerator tokenGenerator)
{
    Configuration = configuration;
    TokenGenerator = tokenGenerator;
    string token = tokenGenerator.GetToken(); // do something with the token
}

private ITokenGenerator TokenGenerator { get; }
// snip

Then a simple call the TokenGenerator.GetToken() updates the header of the client the factory returns to callers.

For completeness, here is the implementation of the TokenGenerator.cs

public class TokenGenerator : ITokenGenerator
{
    private readonly IMemoryCache _memoryCache;
    public TokenGenerator(IMemoryCache memoryCache)
    {
        _memoryCache = memoryCache;
    }

    public string GetToken()
    {
        string token;
        if (_memoryCache.TryGetValue("Token", out token))
        {
            return token;
        }
        else
        {
            // here you would have a more realistic way of generating a new token
            token = Guid.NewGuid().ToString();
            _memoryCache.Set("Token", token, TimeSpan.FromSeconds(10));

            return token;
        }
    }
}

Full source code here.

Caching in Polly and the HttpClientFactory

Full source code here.

Polly allows you to cache a response for reuse by a subsequent request, it supports both local an distributed caches, full information can be found here https://github.com/App-vNext/Polly/wiki/Cache.

The HttpClientFactory lets you define polices in startup.cs and apply them to HttpClient requests anywhere in your application. With most policies this makes it easier for you to apply a policy to a request, but with the cache policy it complicates matters.

With the release of HttpClientFactory there are now two ways to use the cache policy, one taking advantage of HttpClientFactory to apply the policy to requests, and the other bypassing it when executing requests.

Caching with the cache policy inside the HttpClientFactory
First let’s look at how to use the Cache Policy using PolicySelector method on the HttpClientFactory to apply the policy to the request, see this post for more info.

If you are working in Polly V6+ add Polly.Caching.Memory package to your project, this is important, don’t add Polly.Caching.MemoryCache that is for Polly V5.9 and earlier, and many an hour was lost figuring that out.

In Startup.cs add the following to the ConfigureServices method –

public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
    services.AddSingleton<IAsyncCacheProvider, MemoryCacheProvider>();

    IPolicyRegistry<string> registry = services.AddPolicyRegistry();

    services.AddHttpClient("RemoteServer", client =>
    {
        client.BaseAddress = new Uri("http://localhost:5000/api/");
        client.DefaultRequestHeaders.Add("Accept", "application/json");
    }).AddPolicyHandlerFromRegistry(PolicySelector);

This sets up the in memory cache and policy registry, adding both to ServicesCollection. The cache policy is not added here, instead it is added in the Configure(..) method (thanks Andrew Lock for reminding me about this).

Next, add the HttpClientFactory and a method to pick the appropriate policy from the registry.

Inside the Configure(..) I setup the cache policy. The registry and cache provider are passed via dependency injection.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
    IAsyncCacheProvider cacheProvider, IPolicyRegistry<string> registry)
{
    CachePolicy<HttpResponseMessage> cachePolicy = 
        Policy.CacheAsync<HttpResponseMessage>(cacheProvider, TimeSpan.FromSeconds(30));
    registry.Add("CachingPolicy", cachePolicy);

In the controller I have a constructor that takes one argument, the HttpClientFactory.

public CatalogController(IHttpClientFactory httpClientFactory)
{
    _httpClientFactory = httpClientFactory;
}

In the action method I get the HttpClient from the HttpClientFactory and specify the remote endpoint I want to call, but now I can’t use usual httpClient.GetAsync(..) because I can’t pass it a cache context key (i.e. the name of where I look for previously cached responses and store new responses).
Instead I build a HttpRequestMessage, specifying the HttpMethod, Uri and using a Polly extension method I set the cache context.

HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, 
    new System.Uri(httpClient.BaseAddress + requestEndpoint));

httpRequestMessage.SetPolicyExecutionContext(new Context($"GetInventoryById-{id}"));

HttpResponseMessage response = await httpClient.SendAsync(httpRequestMessage);

This approach feels a bit awkward and not many people use the HttpRequestMessage to send requests to remote services.

Caching with the cache policy outside the HttpClientFactory
An alternative to the above is to add the cache to the registry, but not add the registry to the HttpClientFactory.

In this case the adding the HttpClientFactory to the services collection changes slightly –

services.AddHttpClient("RemoteServer", client =>  
{
    client.BaseAddress = new Uri("http://localhost:5000/api/");
    client.DefaultRequestHeaders.Add("Accept", "application/json");
}); // no policy selector

In the controller we now pass in the registry as HttpClientFactory as constructor arguments.

public StockMgtController(IHttpClientFactory httpClientFactory, IPolicyRegistry<string> policyRegistry) 
{
    _httpClientFactory = httpClientFactory;
    _policyRegistry = policyRegistry;
}

There are changes inside the action method also –

[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
    string requestEndpoint = $"inventory/{id}";
    var httpClient = _httpClientFactory.CreateClient("RemoteServer");

    var cachePolicy = _policyRegistry.Get<CachePolicy<HttpResponseMessage>>("CachingPolicy");
    Context policyExecutionContext = new Context($"GetInventoryById-{id}");

    HttpResponseMessage response = await cachePolicy.ExecuteAsync(
        context => httpClient.GetAsync(requestEndpoint), policyExecutionContext);
	//snip..	

The httpClient is retrieved from the HttpClientFactory as before, but now the cachePolicy is taken from the policy registry, the Context is defined and then we use the cachePolicy.ExecuteAsync(..) method to make call the httpClient.GetAsync(..) method.

The other way
You might have noticed that there is another way of using the cache policy. You could use the HttpClientFactory and a PolicySelector method to apply most policies to your HttpClient requests, but not for the cache policy. I wouldn’t do this, it will confuse everyone.

Conclusion
The outcome of both is the same, I think the first approach is better, even though the call to the httpClient is a little more convoluted, it will be more consistent with how you call other policies in your application, there is also a chance the Polly team will add an extension method to make the use of HttpRequestMessage transparent to us developers.

Full source code here.

Alter response header in Web API to return machine name

Full source code available here.

I recently hit a problem where I was getting incorrect responses from a server behind a load balancer. Looking at the logs didn’t help because there was no error.

It was likely due to a misconfigured environmental variable but I couldn’t even identify which server was having the problem because of the load balancer.

Luckily the application was a .NET Core Web Api and I could use a little bit of middleware to add the server name to the response header.

It’s a trivial change in the Configure(..) method of Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.Use((context, next) =>
    {
        context.Response.Headers.Add("MachineName", $"{Environment.MachineName}");
        return next();
    });
    app.UseMvc();
}

That’s all I had to do.

Here’s how the response looks now.

.

Full source code available here.

Polly, HttpClientFactory and the Policy Registry in a console application

Full source code available here.

How to use the HttpClientFactory with a console application is not immediately obvious. I thought it would be a simple matter, but it’s not because it relies on the dependency injection infrastructure you get with a web application. I’ve written about using HttpClientFactory with Polly in a Web Api here.

The easiest way to use HttpClientFactory within a console application is inside a HostBuilder. This gives you access to the services collection, now everything is easy.

Start with a standard console application, if you’re wondering about the async Task on my Main method, this was introduced in C# 7.1.

static async Task Main(string[] args)
{
    var builder = new HostBuilder()
        .ConfigureServices((hostContext, services) =>
        {

Inside the ConfigureServices, we configure the HttpClientFactory in the same way I showed in my previous post. You can also configure other things like logging, configuration sources, more DI, etc.

But first off, I’m going to add a Polly registry –

IPolicyRegistry<string> registry = services.AddPolicyRegistry();
	
IAsyncPolicy<HttpResponseMessage> httWaitAndpRetryPolicy =
    Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
        .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(retryAttempt));

registry.Add("SimpleWaitAndRetryPolicy", httWaitAndpRetryPolicy);

IAsyncPolicy<HttpResponseMessage> noOpPolicy = Policy.NoOpAsync()
    .AsAsyncPolicy<HttpResponseMessage>();

registry.Add("NoOpPolicy", noOpPolicy);

Then add the HttpClientFactory, passing in the lambda to pick the right policy based on the HTTP verb.

services.AddHttpClient("JsonplaceholderClient", client =>
{
    client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com");
    client.DefaultRequestHeaders.Add("Accept", "application/json");
}).AddPolicyHandlerFromRegistry((policyRegistry, httpRequestMessage) =>
{
    if (httpRequestMessage.Method == HttpMethod.Get || httpRequestMessage.Method == HttpMethod.Delete)
    {
        return policyRegistry.Get<IAsyncPolicy<HttpResponseMessage>>("SimpleWaitAndRetryPolicy");
    }
    return policyRegistry.Get<IAsyncPolicy<HttpResponseMessage>>("NoOpPolicy");
});

Next, add the hosted service we want to start.

services.AddSingleton<IHostedService, BusinessService>();

A hosted service is a class that implements IHostedService, more on this below.

Finally at the end of the the Main method, start the hosted service.

await builder.RunConsoleAsync();

For clarity, here is the full listing of the main method –

static async Task Main(string[] args)
{
    var builder = new HostBuilder()
        .ConfigureServices((hostContext, services) =>
        {
            IPolicyRegistry<string> registry = services.AddPolicyRegistry();

            IAsyncPolicy<HttpResponseMessage> httWaitAndpRetryPolicy =
                Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
                    .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(retryAttempt));

            registry.Add("SimpleWaitAndRetryPolicy", httWaitAndpRetryPolicy);

            IAsyncPolicy<HttpResponseMessage> noOpPolicy = Policy.NoOpAsync()
                .AsAsyncPolicy<HttpResponseMessage>();

            registry.Add("NoOpPolicy", noOpPolicy);

            services.AddHttpClient("JsonplaceholderClient", client =>
            {
                client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com");
                client.DefaultRequestHeaders.Add("Accept", "application/json");
            }).AddPolicyHandlerFromRegistry((policyRegistry, httpRequestMessage) =>
            {
                if (httpRequestMessage.Method == HttpMethod.Get || httpRequestMessage.Method == HttpMethod.Delete)
                {
                    return policyRegistry.Get<IAsyncPolicy<HttpResponseMessage>>("SimpleWaitAndRetryPolicy");
                }
                return policyRegistry.Get<IAsyncPolicy<HttpResponseMessage>>("NoOpPolicy");
            });
                
            services.AddSingleton<IHostedService, BusinessService>();
        });

    await builder.RunConsoleAsync();
}

The hosted service
The hosted service is where you put your business logic, it is a simple c# class that implements IHostedService giving it two methods, StartAsync and StopAsync.

Its constructor takes an IHttpClientFactory as a parameter, which is satisfied by the dependency injection infrastructure.

public BusinessService(IHttpClientFactory httpClientFactory)
{
    _httpClientFactory = httpClientFactory;
}

From StartAsync, you can do anything you need.

In this example I call another method which in turn uses the HttpClientFactory to get an instance of a HttpClient to make requests to the the remote server. The requests are executed inside the appropriate Polly policy.

public async Task StartAsync(CancellationToken cancellationToken)
{
    await MakeRequestsToRemoteService();
}

public async Task MakeRequestsToRemoteService()
{
    HttpClient httpClient = _httpClientFactory.CreateClient("JsonplaceholderClient");
    var response = await httpClient.GetAsync("/photos/1");
    Photo photo = await response.Content.ReadAsAsync<Photo>();
    Console.WriteLine(photo);
}

Full source code available here.

Polly, HttpClientFactory and the Policy Registry – choosing the right policy based on the HTTP request

Full source code available here.

The release of .NET Core 2.1 has made using HttpClient much easier. If you have been using HttpClient for a while you will know about its limitations around reuse and DNS expiry, I wrote about this some time ago. The HttpClientFactory takes care of the problems addressed in that post.

Along with those improvements the HttpClientFactory now makes it very easy to add Polly policies that will be executed whenever you create a HttpClient with the factory. This means you define the polices in one place, add them to the factory and forget about them! No more code is needed to add resilience to each of your calls. The factory takes care of creating the client and applying the policy, you can’t even tell that Polly is protecting your call where you make it.

For more on the HttpClientFactory check out Steve Gordon’s series of articles.

A simple example
Here’s a simple example of the HttpClientFactory in use. This adds the factory to our dependency injection container, sets the base address of the remote server and lets us configure the client. It also adds a simple retry policy that checks if the response is NOT a success code and retries up to three times.

services.AddHttpClient("OrderApiServer", client =>
{
    client.BaseAddress = new Uri("http://localhost:57696/api/");
    client.DefaultRequestHeaders.Add("Accept", "application/json");
}).AddPolicyHandler(Policy.HandleResult<HttpResponseMessage>
    (r => !r.IsSuccessStatusCode).RetryAsync(3));

When you create a HttpClient now, it will include the policy.

var httpClient = _httpClientFactory.CreateClient("OrderApiServer");

And when you execute a request it the policy will retry up to three times if necessary.

var result = await httpClient.GetAsync("api/SomeEndpoint);

This might be great if all you are going to is perform GET’s and every call you make is safe and idempotent. But what if you want to use GET, PUT, POST and DELETE, you won’t want to retry all of those requests?

This is easy too. You add a policy registry will all the policies you want to use. Say, a retry policy, a wait and retry policy and no op policy, and provide a selector method to pick the right one based on the HTTP verb (or even the endpoint you are requesting).

Using a Policy Registry with the HttpClientFactory

Step 1

Add the policy registry to the Service Collection and add the policies to the registry.

public void ConfigureServices(IServiceCollection services)
{
    IPolicyRegistry<string> registry = services.AddPolicyRegistry(); // creates the registry and adds it to the service collection

    IAsyncPolicy<HttpResponseMessage> httpRetryPolicy =
        Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
            .RetryAsync(3);

    registry.Add("SimpleHttpRetryPolicy", httpRetryPolicy);

    IAsyncPolicy<HttpResponseMessage> httWaitAndpRetryPolicy =
        Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
            .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(retryAttempt));

    registry.Add("SimpleWaitAndRetryPolicy", httWaitAndpRetryPolicy);

    IAsyncPolicy<HttpResponseMessage> noOpPolicy = Policy.NoOpAsync()
        .AsAsyncPolicy<HttpResponseMessage>();

    registry.Add("NoOpPolicy", noOpPolicy);
    //snip..

Step 2
Now that we have the three polices and the registry, lets add the HttpClientFactory to the Service Collection.

services.AddHttpClient("OrderApiServer", client =>
{
    client.BaseAddress = new Uri("http://localhost:57696/api/");
    client.DefaultRequestHeaders.Add("Accept", "application/json");
}).AddPolicyHandlerFromRegistry(PolicySelector);

Note the PolicySelector, this is the method I use to choose the right policy for each request.

Step 3
This method is simple, it takes the registry and the HttpRequest as arguments and grabs the policy from the registry based on the HTTP verb.

private IAsyncPolicy<HttpResponseMessage> PolicySelector(IReadOnlyPolicyRegistry<string> policyRegistry, HttpRequestMessage httpRequestMessage)
{
    if (httpRequestMessage.Method == HttpMethod.Get)
    {
        return policyRegistry.Get<IAsyncPolicy<HttpResponseMessage>>("SimpleHttpRetryPolicy");
    }
    else if (httpRequestMessage.Method == HttpMethod.Post)
    {
        return policyRegistry.Get<IAsyncPolicy<HttpResponseMessage>>("NoOpPolicy");
    }
    else
    {
        return policyRegistry.Get<IAsyncPolicy<HttpResponseMessage>>("SimpleWaitAndRetryPolicy");
    }
}         

You could use a lambda instead of a method when creating the HttpClientFactory. For example if if you had two policies to choose from –

.AddPolicyHandlerFromRegistry((policyRegistry, message) => policyRegistry.Get<IAsyncPolicy<HttpResponseMessage>>(message.Method == HttpMethod.Get ? "SimpleHttpRetryPolicy" : "NoOpPolicy"));

That’s the hard work done.

Step 4
Let’s take a look at the controller.

public class OrderController : ControllerBase
{
    private readonly IHttpClientFactory _httpClientFactory;

    public OrderController(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }


    [HttpGet("{orderId}")]
    public async Task<ActionResult> Get(int orderId)
    {
        //snip
        string requestEndpoint = $"invoice/{orderId}";

        var httpClient = _httpClientFactory.CreateClient("OrderApiServer");

        HttpResponseMessage response = await httpClient.GetAsync(requestEndpoint);

		//handle response
    }	
}

The only thing I’m passing into the constructor is the HttpClientFactory, I don’t have any Polly using statements.

In the GET method you can’t even tell that there is a policy around the HttpClient.GetAsync(..)

All the Polly work is done in the Startup.cs, the policies are defined, added to the registry, the registry is added to the HttpClientFactory and the HttpClientFactory is added to the services collections.

Now all your HttpClient requests are executed inside a policy.

For more on this, check out Dylan’s Polly and HttpClientFactory documentation.

Full source code available here.

Using Other Verbs with Web API

Full source code available here.

You will often use the GET verb when making requests to an API. You have probably used it like this –

www.example.com/person/ or
www.example.com/person/1 or
www.example.com/person?firstname=dave&lastname=daniels&age=22

All very simple, but what if you wanted to to search for many people at the same time, and I don’t mean all the people aged 22, or all the people with the first name Dave.

What if you wanted to look for Dave, Tom, Steve and Dan in one request, or all the people aged 22, 33, or 44.

You could go down the road of adding them to the query string, something like

www.example.com/person?firstperson_firstname=dave&secondperson_firstname=tom&...

But this a bad idea.

This is where the HTTP SEARCH method comes in. If this doesn’t sound familiar, that might be because it is currently an IETF draft https://tools.ietf.org/html/draft-snell-search-method-00, but tools like Fiddler support it.

SEARCH differs from GET by having a body. In this body you can have any content you want. For our scenario we will use a json body with an array of things to search for. You have to specify in the header what the content type of the body, e.g. Content-Type: application/json, (just like you do with a POST or a PUT).

I’ve created a very simple POCO to represent the things I want to search by.

public class PersonSearchModel
{
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public int Age { get; set; }
}

Into the body of the SEARCH request I have a json array of PersonSearchModel.

[
  {
    "firstname": "Dave",
    "lastname": "Davis",
    "age": 22
  },
  {
    "firstname": "Larry",
    "lastname": "Landers"
  },
  {
    "firstname": "Steve",
    "lastname": "Smith",
    "age": 44
  }
]

Now we can search for as many people as we like in as complicated way as we like.

In the PersonController I have a Search method –

[AcceptVerbs("SEARCH")]
public async Task<IActionResult> Search([FromBody]List<PersonSearchModel> people)
{
	// Perform search
	// snip..
}

Inside the body of the method you can search in any manner you choose.
here.

Full source code available here.

Loading Config from Multiple Sources with .NET Core 2.x Web Api or MVC

Full source code available here.

.NET Core 2 and .NET Core 2.1 offer many ways to load configuration and they are well documented by Microsoft. But there is one scenario that I didn’t see explained.

If you want to supplement the configuration in appsettings.json with more from a remote service, database or some other source, you first need to know where that source is, then make a request to it and add it to your configuration. You are probably going to put the location of the remote configuration appsettings.json, then you call the remote config source.
Sounds easy? It is, but not obvious.

First, a little background.

In an out of the box Web API or MVC application you get a Program.cs that looks like this –

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

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

On line 9, we have WebHost.CreateDefaultBuilder(args), if you peek the definition of this with Resharper you will some something like –

The highlighted code is how your appsettings.json is loaded into the configuration and added to services collection, this call happens just as you leave Program.cs

But you want to read from the appsettings.json and use a value from it to make another call to get more configuration and then add the whole lot of the services collection. You might also want to setup some logging configuration in Program.cs, so you need access to all configuration settings before calling

CreateWebHostBuilder(args).Build().Run();

Here’s how you do it.

Step 1
Inside the main method in Program.cs, build the configuration yourself –

IConfigurationBuilder builder = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json");
Configuration = builder.Build();

Get the location of the other configuration service, in my example it is another json file.
Add it to the builder and call build.

string otherConfigService = Configuration["otherConfigService"]; // this could be a database or something like consul

builder.AddJsonFile(otherConfigService);
Configuration = builder.Build();

Now you have access to the configuration values from the second source.

Configuration["SomeOtherConfigItem1"]}
Configuration["SomeOtherConfigItem2"]}

So far so good, but as mentioned above, the CreateDefaultBuilder adds the configuration to the ServiceCollection, making it available by DI. But that only happens for appsettings.json (and appsettings.{env.EnvironmentName}.json, not the config you loaded from the other source.

If you tried to access the a config setting of your from inside Startup.cs or a controller, it would not be there.

Step 2
Let’s make our configuration available via the ServicesCollection.

In the first block of code above there was a call – CreateWebHostBuilder(args).Build().Run();

I added line 4 below, this will add the configuration to the services collection.

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .UseConfiguration(Configuration); // add this line to add your configuration to the service collection

Now, the config values loaded from appsettings.json and your secondary config source will be available throughout your application.

Full source code available here.

Using the In-Memory Cache with .NET Core Web API

Full source code available here.

If you need to store anything temporarily within an application, you should consider using the In-Memory Cache from Microsoft. In .NET Core it is much easier to use than its predecessor from Framework 4.x. You can store almost anything in it, in a type safe manner.

When adding an item to the cache you set the an expiration, this can be an absolute time, a sliding window or the combination of both. Choosing which one to use depends on your scenario.

When an item is removed from the cache a delegate can be called, you can use this for logging or some other purpose.
Items can also be evicted when the cache is running low on memory.

In this example I’m going to show a simple usage example for the cache inside a .NET Core Web API application.
Just a single line in startup.cs adds the cache to the dependency injection container.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
    services.AddMvc();
}

Now I can access the cache from inside all my controllers by just adding an IMemoryCache parameter to the constructor.

private readonly IMemoryCache _cache;
public CountriesController(IMemoryCache memoryCache)
{
    _cache = memoryCache;
}

I have a very simple GET method that takes a country code as its parameter and looks up full name of the country.

[HttpGet("{countryCode}")]
public async Task<IActionResult> Get(string countryCode)
{
    string country = await LookupCountryByCode(countryCode);

    if (string.IsNullOrEmpty(country))
    {
        return NoContent();
    }
    return Ok(country);
}

And here is where I use the cache.

private async Task<string> LookupCountryByCode(string countryCode)
{
    if(!_cache.TryGetValue("ListOfCountries", out Dictionary<string, string> countries))
    {
        Console.WriteLine("Cache miss....loading from database into cache");
        countries =
            JsonConvert.DeserializeObject<Dictionary<string, string>>(
                await System.IO.File.ReadAllTextAsync("countrylist.json"));

        _cache.Set("ListOfCountries", countries, TimeSpan.FromSeconds(10));
    }
    else
    {
        Console.WriteLine("Cache hit");
    }

    return countries[countryCode];
}

On line 3, I check if the list of countries is in the cache; I won’t be the first time through this method or if the cache entry has expired.
Inside the if clause I load the list of countries from a json file, but you could load from a database or any other source. Then I add the list to the cache and set when the entry will expire, in this example it will expire 10 seconds after it was added.

If you want to use both an absolute expiration and sliding window you need to pass the MemoryCacheEntryOptions when adding an item to the cache.

MemoryCacheEntryOptions options = new MemoryCacheEntryOptions
{
    AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(25), // cache will expire in 25 seconds
    SlidingExpiration = TimeSpan.FromSeconds(5) // caceh will expire if inactive for 5 seconds
};

_cache.Set("ListOfCountries", countries, options);

Full source code available here.

Using Dependency Injection with Startup.cs in ASP.NET Core

Full source code available here.

Did you know that .NET Core 2 can pass in an instance of any type you want to the Startup.cs constructor? Well you can! Here’s how.

Out of the box the Startup.cs comes like this –

public class Startup
{
	public Startup(IConfiguration configuration)
	{
		Configuration = configuration;
	}
//snip..

The IConfiguration is passed in by dependency injection. In Program.cs you can add other types to the DI container, and then add that type to the constructor parameters of Startup.cs.

Here’s how it works. The Microsoft.AspNetCore.Hosting.WebHostBuilder has a ConfigureServices(...) method –

public IWebHostBuilder ConfigureServices(Action<IServiceCollection> configureServices)
{
    if (configureServices == null)
    {
        throw new ArgumentNullException(nameof(configureServices));
    }

    return ConfigureServices((_, services) => configureServices(services));
}

This lets you add services to the dependency injection container from the Program.cs.

WebHost.CreateDefaultBuilder(args) returns an IWebHostBuilder and that lets you use the ConfigureServices(...) method. Easy!

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .ConfigureServices(serviceCollection =>
            serviceCollection.AddScoped<ISomeService, SomeService>())
        .UseStartup<Startup>()
        .Build();

And in Startup.cs

public class Startup
{
    private ISomeService _someService;
    public Startup(IConfiguration configuration, ISomeService someService)
    {
        _someService = someService;
        Configuration = configuration;
    }
// snip..	

The instance of ISomeService is of course available for DI everywhere in the application.

public class ValuesController : Controller
{
    private readonly ISomeService _someService;
    public ValuesController(ISomeService someService)
    {
        _someService = someService;
    }
}

Full source code available here.