Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ObjectDisposedException: The CancellationTokenSource has been disposed

I'm starting to develop with Xamarin.Forms using Xamarin Studio on my MacBook Pro. I built an application whose purpose is to query a PrestaShop Website, retrieve the Products and show them.

When deploying the application to Android, I had some problems with versions below Marshmallow, but I solved them, so I won't describe them here.

When deploying the application to iOS (Simulator), I'm still having a critical problem. The application runs, but when I click on the button to retrieve the data, it crashes giving me a System.ObjectDisposedException, whose message is "The CancellationTokenSource has been disposed". I'll paste here the relevant source code:

async void button1_Click(object sender, System.EventArgs e)
{
    try
    {
        HttpClientHandler hnd = new HttpClientHandler();
        hnd.Credentials = new NetworkCredential("[apikey]", "");
        string res;
        using (var client = new HttpClient(hnd))
        {
            var responseText = await client.GetStringAsync("[endpoint]/products");
            using (MemoryStream stream = new MemoryStream())
            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write(responseText.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", string.Empty));
                writer.Flush();
                stream.Position = 0;
                XDocument doc = XDocument.Load(stream);
                res = JsonConvert.SerializeXNode(doc, Formatting.Indented, true);
            }
            var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(res);
            //Result.Text = data["products"].GetType().ToString() + Result.Text;
            Func<string, Task> creator_method = async (string id) =>
            {
                try
                {
                    var responseProd = await client.GetStringAsync($"[endpoint]/products/{id}"); // AT THIS ROW THE EXCEPTION IS RAISED!!!
                    using (MemoryStream stream = new MemoryStream())
                    using (StreamWriter writer = new StreamWriter(stream))
                    {
                        writer.Write(responseProd.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", string.Empty));
                        writer.Flush();
                        stream.Position = 0;
                        XDocument doc = XDocument.Load(stream);
                        res = JsonConvert.SerializeXNode(doc, Formatting.Indented, true);
                    }
                    var product_rawData = JsonConvert.DeserializeObject<Dictionary<string, object>>(res);
                    var productData = (JObject)product_rawData["product"];
                    try
                    {
                        views.Children.Add(new ProductXaml(productData["name"]["language"]["#cdata-section"].ToString(), float.Parse(productData["price"]["#cdata-section"].ToString().Replace('.', ',')), productData["id_default_image"]["@xlink:href"].ToString()));
                    }
                    catch (NullReferenceException nre)
                    {
                        views.Children.Add(new ProductXaml(productData["name"]["language"]["#cdata-section"].ToString(), float.Parse(productData["price"]["#cdata-section"].ToString().Replace('.', ',')), ""));
                    }
                }
                catch (Exception gex) { throw; }
            };
            foreach (var product in ((JObject)data["products"])["product"])
                try
                {
                    Device.BeginInvokeOnMainThread(async () => { await creator_method.Invoke(product["@id"].ToString()); });
                }
                catch (TaskCanceledException tce) { continue; }
                catch (WebException we) { continue;}
        }
    }
    catch (HttpRequestException ex)
    {
        Result.Text = ex.Message;
    }
}

How could I solve the problem?

like image 330
jinzo78 Avatar asked Jun 24 '16 09:06

jinzo78


People also ask

When should I dispose of CancellationTokenSource?

Call Dispose when you are finished using the CancellationTokenSource. The Dispose method leaves the CancellationTokenSource in an unusable state.

What is difference between CancellationTokenSource and CancellationToken?

CancellationTokenSource - This is the object responsible for creating a cancellation token and sending a cancellation request to all copies of that token. CancellationToken - This is the structure used by listeners to monitor the token's current state.

What happens when CancellationToken is Cancelled?

The associated CancellationToken will be notified of the cancellation and will transition to a state where IsCancellationRequested returns true. Any callbacks or cancelable operations registered with the CancellationToken will be executed.

What is CancellationTokenSource in C#?

A CancellationTokenSource object, which provides a cancellation token through its Token property and sends a cancellation message by calling its Cancel or CancelAfter method. A CancellationToken object, which indicates whether cancellation is requested.


1 Answers

"The CancellationTokenSource has been disposed"

It seems that your using (var client = new HttpClient())...'s CancellationToken has already been consumed by the first client.GetStringAsync() call.

How To Fix This
I would suggest putting your second call in its own using block, to avoid this.

Here's what your code should now look like, with a second using statement:

async void button1_Click(object sender, System.EventArgs e)
{
    try
    {
        HttpClientHandler hnd = new HttpClientHandler();
        hnd.Credentials = new NetworkCredential("[apikey]", "");
        string res;
        using (var client = new HttpClient(hnd))
        {
            var responseText = await client.GetStringAsync("[endpoint]/products");
            using (MemoryStream stream = new MemoryStream())
            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write(responseText.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", string.Empty));
                writer.Flush();
                stream.Position = 0;
                XDocument doc = XDocument.Load(stream);
                res = JsonConvert.SerializeXNode(doc, Formatting.Indented, true);
            }
            var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(res);
            //Result.Text = data["products"].GetType().ToString() + Result.Text;
            Func<string, Task> creator_method = async (string id) =>
            {
                try
                {
                    using (var newClient = new HttpClient(hnd)) // Create a new client to avoid your other one's token being consumed
                    {
                        var responseProd = await newClient.GetStringAsync($"[endpoint]/products/{id}");
                        using (MemoryStream stream = new MemoryStream())
                        using (StreamWriter writer = new StreamWriter(stream))
                        {
                            writer.Write(responseProd.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", string.Empty));
                            writer.Flush();
                            stream.Position = 0;
                            XDocument doc = XDocument.Load(stream);
                            res = JsonConvert.SerializeXNode(doc, Formatting.Indented, true);
                        }
                        var product_rawData = JsonConvert.DeserializeObject<Dictionary<string, object>>(res);
                        var productData = (JObject)product_rawData["product"];
                        try
                        {
                            views.Children.Add(new ProductXaml(productData["name"]["language"]["#cdata-section"].ToString(), float.Parse(productData["price"]["#cdata-section"].ToString().Replace('.', ',')), productData["id_default_image"]["@xlink:href"].ToString()));
                        }
                        catch (NullReferenceException nre)
                        {
                            views.Children.Add(new ProductXaml(productData["name"]["language"]["#cdata-section"].ToString(), float.Parse(productData["price"]["#cdata-section"].ToString().Replace('.', ',')), ""));
                        }
                    }
                }
                catch (Exception gex) { throw; }
            };
            foreach (var product in ((JObject)data["products"])["product"])
                try
                {
                    Device.BeginInvokeOnMainThread(async () => { await creator_method.Invoke(product["@id"].ToString()); });
                }
                catch (TaskCanceledException tce) { continue; }
                catch (WebException we) { continue;}
        }
    }
    catch (HttpRequestException ex)
    {
        Result.Text = ex.Message;
    }
}

Hope this helps! :)

like image 200
Geoff James Avatar answered Oct 17 '22 06:10

Geoff James