6

When using Flurl.Http v1.2 we had the following code:

1. var cookieJar = new CookieContainer();
2. var url = baseUrl.AppendPathSegment("api/auth/login");
3. var client = url.EnableCookies();
4. ((HttpClientHandler)client.HttpMessageHandler).CookieContainer = cookieJar;
5. var result = await client.PostJsonAsync(new { UserName = userName, Password = password });
6. var cookies = cookieJar.GetCookies(new Uri(baseUrl));
7. _cookie = cookies[0];

After upgrading to v2.0.1 line 4 no longer compiles because client is no longer an IFlurlClient it's now an IFlurlRequest, as per the release notes.

I noticed that IFlurlRequest has a Client property, so I changed line 4 to be:

4. ((HttpClientHandler)client.Client.HttpMessageHandler).CookieContainer = cookieJar;

That now compiles but fails at run-time with an InvalidOperationException:

This instance has already started one or more requests. Properties can only be modified before sending the first request.

I'm assuming that's because of the aggressive reuse of the underlying HttpClient. I added a line between 3 and 4 to create a new FlurlClient each time to ensure the instance could not have started a request.

1. var cookieJar = new CookieContainer();
2. var url = baseUrl.AppendPathSegment("api/auth/login");
3. var request = url.EnableCookies();
3.5 request.Client = new FlurlClient();
4. ((HttpClientHandler)request.Client.HttpMessageHandler).CookieContainer = cookieJar;
5. var result = client.PostJsonAsync(new { UserName = userName, Password = password }).Result;
6. var cookies = cookieJar.GetCookies(new Uri(baseUrl));
7. _cookie = cookies[0];

This now works again, but I'm not sure I'm doing this the correct way. Any feedback would be appreciated.

Craig W.
  • 17,838
  • 6
  • 49
  • 82

1 Answers1

9

You shouldn't need to manage CookieContainer explicitly; Flurl makes working with cookies a lot simpler.

Generally you want to reuse HttpClient instances as much as possible, and 2.0 does do this for you by default when you don't create FlurlClients explicitly, but in the case of persisting cookies over multiple calls you're probably going to want to manage FlurlClient yourself, otherwise multiple threads could be reading/writing cookies on the same collection.

Still pretty easy. I think your whole example can be reduced to this:

using (var cli = new FlurlClient(baseUrl).EnableCookies()) {
    await cli.Request("api/auth/login").PostJsonAsync(new {
        UserName = userName,
        Password = password });
    _cookie = cli.Cookies.First().Value;
}
Todd Menier
  • 37,557
  • 17
  • 150
  • 173
  • Worked great. I did have to change `cli.Cookies[0]` to `cli.Cookies.First().Value` because the `Cookies` collection is a dictionary. I could also have indexed into it using the name of the cookie but figured I'd go this other route in case the cookie name changed. – Craig W. Nov 14 '17 at 23:23