I'm using the Furl.Http wrapper over the .NET Http Client. With each request my API requires a User-Agent and an Authorization header to be sent.
I would like to set that up once, rather than having to state that every time.
What I thought I would be able to do is create an instance of the FlurlClient and set the headers on it, then ResetToRoot before each request, as illustrated in this sample piece of code:
var fc = new FlurlClient();
fc.WithHeader("User-Agent", "Keep/1.0");
var tokenModel = await
"https://app.tempuri.com".AppendPathSegment("auth")
.WithClient(fc)
.PostUrlEncodedAsync(new { username = "you", password = "secret"})
.ReceiveJson<TokenModel>();
fc.WithHeader("Authorization",
string.Format("Token {0}",tokenModel.Token));
fc.Url.ResetToRoot();
var userModel = await fc.Url
.AppendPathSegment("auth").GetJsonAsync<UserModel>();
Console.WriteLine(userModel.Username);
However it would appear that after the RestToRoot()
the headers are no longer sent.
Is this by design? Is there a better approach to insuring these headers are sent on each request?
The problem is the second-to-last line.
fc.Url...GetJsonAsync
FlurlClient
has a reference to the Url
object, but not vice-versa, so by the time you call fc.Url
, you've effectively lost that reference and a new FlurlClient
is created behind the scenes when you call GetJsonAsync
. This is by design in that Flurl.Url
is a simple builder class in the core Flurl library that can be used independently of Flurl.Http.
Here's how I'd do it:
var url = "https://app.tempuri.com";
using (var fc = new FlurlClient().WithHeader("User-Agent", "Keep/1.0")) {
var tokenModel = await url
.AppendPathSegment("...")
.WithClient(fc)
.PostUrlEncodedAsync(new { username = "you", password = "secret"})
.ReceiveJson<TokenModel>();
fc.WithHeader("Authorization",
string.Format("Token {0}",tokenModel.Token));
var userModel = await url
.AppendPathSegment("...")
.WithClient(fc)
.GetJsonAsync<UserModel>();
Console.WriteLine(userModel.Username);
}
A couple notes:
FlurlClient
in each HTTP call.url
variable is just a string, so there's no need to call ResetToRoot
.using
statement is not absolutely required here but it is good practice.