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:
- Notice you're attaching the
FlurlClient
in each HTTP call.
- Here the
url
variable is just a string, so there's no need to call ResetToRoot
.
- The
using
statement is not absolutely required here but it is good practice.
There is an alternative approach that would work too. For each successive HTTP call, modify fc.Url
first, then use fc
to make the call:
fc.Url.ResetToRoot().AppendPathSegment(...);
var x = await fc.GetJsonAsync<T>();
In this case you would need to call ResetToRoot
but not WithClient
. The fluent chain is broken here but you might find it more readable. Either way works, just a matter of personal preference.