What is the appropriate way to store a CookieContainer to persist throughout app lifecycle?

ErikR.9376ErikR.9376 USUniversity
edited May 2016 in Xamarin.Forms

I'll preface this question with I'm new to C# and Xamarin, and working on my first Xamarin Forms app, targeting iOS and Android.

The app is using HttpClient to pass requests to an api, and the headers in the response return session cookies that are used to identify the current user. So once I've received an initial response and those cookies have been stored in the CookieContainer, I want to store that CookieContainer in some global scope so it can be reused and passed with all subsequent requests.

I've read that attempting to serialize the cookies data can be problematic, and HttpOnly cookies are included in the response, which I apparently can't access in the CookieContainer. Because of this, I've also tried enumerating through the values returned in the Set-Cookie header and storing it as a comma delimited string, then using SetCookies on the CookieContainer with that string for subsequent requests. But that seems overly complex and trying to do so results in a consistent, vague error "Operation is not valid due to the current state of the object." when requests are made. So I'm hoping to simply reuse the entire CookieContainer object.

So more pointedly, my questions are:

  1. Where is an appropriate place to store a CookieContainer object so that it will persist throughout the app's lifecycle, and preferably still be available when the app goes into the background and is resumed. Is simply declaring it as a static variable in my WebServices class good enough?

  2. If I do reuse the CookieContainer in this way, will the individual cookies be automatically updated on subsequent requests if more are added or the values of existing ones sent by the server change?

Here's a snippet from the method we're currently using (excluding my attempts at parsing the cookies into a string, which hopefully is unnecessary):

HttpResponseMessage httpResponse;

var cookieContainer = new CookieContainer (); // want to set/store this globally
var baseAddress = new Uri("http://www.test.com");

using (var handler = new HttpClientHandler () { CookieContainer = cookieContainer })
using (HttpClient client = new HttpClient (handler) { BaseAddress = baseAddress })
{
    // has a timeout been set on this Web Service instance? 
    if (TimeoutSeconds > 0) {
        client.Timeout = new System.TimeSpan(0,0,TimeoutSeconds);
    }

    // Make request (the "uri" var is passed with the method call)
    httpResponse = await client.GetAsync (uri);
}

Answers

  • ErikR.9376ErikR.9376 USUniversity

    Can't seem to edit my initial post any more, but want to make a couple of corrections:

    1. Serializing seems to be problematic because of not being able to read/access the HttpOnly cookies. Please correct me if I'm wrong here. I've been having difficulty implementing serialization since the concept is new to me, so any direction on that would be super helpful. I've been having trouble with examples I've found, in part because of namespace references not being recognized in Xamarin studio. For example, I get an unknown resolve error trying to include System.Runtime.Serialization.Formatters.Binary. I was able to serialize into a json string, but I did not see the HttpOnly cookies there so didn't go any further.

    2. It is actually a requirement, not just a preference, that the cookies persist in the app even if it is shut down and restarted, so it seems I need to store in something like Application.Current.Properties (as opposed to just a static member of the class). But it seems you can't store an object that way.

  • TravyDaleTravyDale USMember ✭✭

    I do something similar. This is all off memory so I am sorry for the generalized answer. Anyway, I extract the cookie from the CookieStore object when I initially authenticate the user. I store it in my app settings (I use the Settings Plugin by James Montemagno). So whenever I do an API request, I plug in the cookie I saved and use that. If the request fails, I check why and if it is due to the cookie being timed out, I reauth the user and store a new cookie. Isn't the best solution but it is something that works.

  • ErikR.9376ErikR.9376 USUniversity

    Thanks for the suggestion, Travis. I'll look into that plugin - if that allows us to store an object it may be what I'm looking for, since Application.Current.Properties only seems to allow primitive types.

  • TravyDaleTravyDale USMember ✭✭

    I think it is just the basic types. You will probably have to disassemble it and save it to its own individual pieces and then reassemble when you try to get the data back. Although, I only save the cookie string. I dont save everything within the CookieStore object.

  • ChristineZuckermanChristineZuckerman USMember ✭✭✭

    @TravyDale how do you put the cookies into your API Request? I can save them and iOS accesses them, but I can't get Android to recognize them. Thanks!

  • HistoryaHistorya USMember ✭✭✭

    @ChristineBlanda did find a way to that? (in all platforms)

Sign In or Register to comment.