Scott Hanselman

Using ASP.NET Core 2.1's HttpClientFactory with Refit's REST library

June 20, 2018 Comment on this post [11] Posted in ASP.NET | ASP.NET Web API | DotNetCore | Open Source
Sponsored By

Strong by Lucyb_22 used under Creative Commons from FlickrWhen I moved my podcast site over to ASP.NET Core 2.1 I also started using HttpClientFactory and wrote up my experience. It's a nice clean way to centralize both settings and policy for your HttpClients, especially if you're using a lot of them to talk to a lot of small services.

Last year I explored Refit, an automatic type-safe REST library for .NET Standard. It makes it super easy to just declare the shape of a client and its associated REST API with a C# interface:

public interface IGitHubApi
Task<User> GetUser(string user);

and then ask for an HttpClient that speaks that API's shape, then call it. Fabulous.

var gitHubApi = RestService.For<IGitHubApi>("");

var octocat = await gitHubApi.GetUser("octocat");

But! What does Refit look like and how does it work in an HttpClientFactory-enabled world? Refit has recently been updated with first class support for ASP.NET Core 2.1's HttpClientFactory with the Refit.HttpClientFactory package.

Since you'll want to centralize all your HttpClient configuration in your ConfigureServices method in Startup, Refit adds a nice extension method hanging off of Services.

You add a RefitClient of a type, then add whatever other IHttpClientBuilder methods you want afterwards:

.ConfigureHttpClient(c => c.BaseAddress = new Uri(""));
// Add additional IHttpClientBuilder chained methods as required here:
// .AddHttpMessageHandler<MyHandler>()
// .SetHandlerLifetime(TimeSpan.FromMinutes(2));

Of course, then you can just have your HttpClient automatically created and passed into the constructor. You'll see in this sample from their GitHub that you get an IWebAPI (that is, whatever type you want, like my IGitHubApi) and just go to town with a strongly typed interfaces of an HttpClient with autocomplete.

public class HomeController : Controller
public HomeController(IWebApi webApi)
_webApi = webApi;

private readonly IWebApi _webApi;

public async Task<IActionResult> Index(CancellationToken cancellationToken)
var thing = await _webApi.GetSomethingWeNeed(cancellationToken);

return View(thing);

Refit is easy to use, and even better with ASP.NET Core 2.1. Go get Refit and try it today!

* Strong image by Lucyb_22 used under Creative Commons from Flickr

Sponsor: Check out dotMemory Unit, a free unit testing framework for fighting all kinds of memory issues in your code. Extend your unit testing with the functionality of a memory profiler.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
June 21, 2018 5:31

How is it that you ALWAYS end up having a blog post about something that's extremely beneficial to me? 🤔
June 21, 2018 11:09

Have you checked the security settings on your webcam? ;)

(He's darned good at it, isn't he?)
June 21, 2018 12:27
Thanks for highlighting this! Refit is one of my most used libraries and I hadn't seen this was available yet, I'm going in!!
June 21, 2018 17:10
Scott, you should check out Swagger and use a tool to generate these API calls instead of doing it by hand.
June 22, 2018 13:25
This is one of the libraries I have encouraged my coworkers to use anytime we need to make rest calls. They had questions about the HttpClient and Refit has been able to accept a preconfigured HttpClient for a while but this is a nice extension for DI purposes. I just appreciate how simple it is to use.
June 22, 2018 19:03
Hi Scott, have you checked out Flurl and Flurl.Http? Flurl is a nice library for concatenating URL's together (similar in concept to System.IO.Path.Combine). Flurl.Http builds on top of that to make it simple to post/receive data from an HTTP endpoint. Below is an example of both in action.

var person = await ""
.SetQueryParams(new { a = 1, b = 2 })
first_name = "Frank",
last_name = "Underwood"
June 23, 2018 4:38
HttpClientFactory doesn't strike me as something to celebrate--at best, it's a workaround for stortcomings in ASP.NET Core's dirt-simple DI framework. Support for named instances of a type should have been built in on day one (like in Unity Container).

So we're going to keep running into this... prepare to see more factory layers piled on for people who want to connect to multiple Redis caches, etc...
June 24, 2018 3:31
More often than not, tipsters, readers, friends, and kinsfolk of Eater be suffering with unified without a doubt: Where should one break bread vindicate now? Restaurant obsessives miss to grasp what’s new, what’s live, which favorite chef just launched a sophomore effort. And while the Eater 38 is a important resource covering old standbys and neighborhood essentials across the bishopric, it is not a history of the “it” places of the moment. Therefore, the pikestaff offers the Eater Heatmap, which will difference on a methodical basis to again Chicago's Top Restaurants highlight where the crowds are flocking to at the moment.
June 27, 2018 11:43
Hey Scott,

thanks for the nice article. I need to authenticate against the API and I know how it's done in general, but how to define the "AuthorizationHeaderValueGetter" in the Startup.cs? Within a RazorPage I cann get the token with:
var accessToken = await HttpContext.GetTokenAsync("access_token");
but in the Startup.cs when configuring DI I do not hav a HttpContext yet:
services.AddRefitClient<IPolicyServerApi<Policy>>(new RefitSettings { AuthorizationHeaderValueGetter = () => Task.FromResult("TOKEN")}).ConfigureHttpClient(c => c.BaseAddress = new Uri("http://localhost:5001"));
Does anyone have a hint for me? Thanks!
July 05, 2018 2:29
How is it that you ALWAYS end up having a blog post
July 05, 2018 2:30
HttpClientFactory doesn't strike me as something to celebrate--at best, it's a workaround

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.