2

I am trying to solve an issue with one of my Smart Device projects (.NET CF 3.5 on Windows Mobile 6.5 Device).

The code tries to make webservice calls continuously to get some data and use it in the form. During the usage, for a particular case is an ObjectDisposedException thrown and the application crashes. The stacktrace is

System.ObjectDisposedException was unhandled
 Message="ObjectDisposedException"
 ObjectName=""
 StackTrace:
      at System.Threading.Timer.throwIfDisposed()
      at System.Threading.Timer.Change(UInt32 dueTime, UInt32 period)
      at System.Threading.Timer.Change(Int32 dueTime, Int32 period)
      at System.Net.HttpWebRequest.startReadWriteTimer()
      at System.Net.HttpWebRequest.ConnectionClient.Read(Byte[] data, Int32 offset, Int32 length)
      at System.Net.HttpReadStream.NetworkRead(Byte[] data, Int32 offset, Int32 length)
      at System.Net.ChunkedReadStream.fillBuffer()
      at System.Net.ChunkedReadStream.getLine()
      at System.Net.ChunkedReadStream.doRead(Byte[] data, Int32 offset, Int32 length)
      at System.Net.HttpReadStream.ReadToDrain(Byte[] buffer, Int32 offset, Int32 length)
      at System.Net.HttpReadStream.doClose()
      at System.Net.HttpReadStream.Finalize()

I have read many blogs and forums, including this, and the solution suggested seems to be to close the request stream and the request, before getting the response.

requestStream = webRequest.GetRequestStream();
requestStream.Close(); // WE NEED THIS LINE in order to avoid the ObjectDisposedException.

But this does not help my situation. If the requestStream is closed before writing to the data to the stream then it does not do anything. If I close after getting the response, then it throws InvalidOperationException.

Following is my code:

Reference.cs

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="ProductResolveServiceSOAP11Binding", Namespace="urn:ProductResolveService")]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(Exception))]
public partial class ProductResolveService : System.Web.Services.Protocols.SoapHttpClientProtocol {

    /// <remarks/>
    public ProductResolveService() {
        this.Url = "http://172.26.37.115:8080/axis/services/ProductResolveService";
    }

    /// <remarks/>
    [System.Web.Services.Protocols.SoapDocumentMethodAttribute("urn:getResolvedEpcs", RequestNamespace="http://services.axis.oatsystems.com", ResponseNamespace="http://services.axis.oatsystems.com", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
    [return: System.Xml.Serialization.XmlElementAttribute("return", IsNullable=true)]
    public ResolvedProductList getResolvedEpcs([System.Xml.Serialization.XmlElementAttribute(IsNullable=true)] EpcToResolve message) {
        object[] results = this.Invoke("getResolvedEpcs", new object[] {
                    message});
        return ((ResolvedProductList)(results[0]));
    }

    /// <remarks/>
    public System.IAsyncResult BegingetResolvedEpcs(EpcToResolve message, System.AsyncCallback callback, object asyncState) {
        return this.BeginInvoke("getResolvedEpcs", new object[] {
                    message}, callback, asyncState);
    }

    /// <remarks/>
    public ResolvedProductList EndgetResolvedEpcs(System.IAsyncResult asyncResult) {
        object[] results = this.EndInvoke(asyncResult);
        return ((ResolvedProductList)(results[0]));
    }
}

Form1.cs

using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Web.Services.Protocols;
using System.Windows.Forms;
using NFEHandlingProject.StatusService;
using System.IO;
using MVProductResolveService;


namespace NFEHandlingProject
{
    public partial class Form1 : Form
    {
        private Thread resolveThread;
        int counter = 0;

        public Form1()
        {
            InitializeComponent();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            if (resolveThread == null)
            {
                this.BeginInvoke((Action)delegate { lstbxStatusMsgs.Items.Add("Resolve Product: Creating Thread"); lstbxStatusMsgs.SelectedIndex = lstbxStatusMsgs.Items.Count - 1; });

                resolveThread = new Thread(new ThreadStart(GetEpcProductMapping));
                resolveThread.IsBackground = true;
                resolveThread.Priority = ThreadPriority.BelowNormal;

                resolveThread.Start();
            }
        }

        object syncRoot2 = new object();
        bool resolving = false;

        private void GetEpcProductMapping()
        {
            lock (syncRoot2)
            {
                if (resolving)
                {
                    return;
                }

                resolving = true;
            }

            while (resolving)
            {
                using (ProductResolveService2 productResolveService = new ProductResolveService2())
                {
                    EpcToResolve epcToResolve = null;

                    try
                    {
                        this.BeginInvoke((Action)delegate { lstbxStatusMsgs.Items.Add("Resolve Product: Resolving..."); lstbxStatusMsgs.SelectedIndex = lstbxStatusMsgs.Items.Count - 1; });

                        productResolveService.Url = "http://172.26.37.115:8080/axis/services/ProductResolveService?wsdl";

                        productResolveService.Timeout = 60000;

                        // The input object that is sent to xpress
                        epcToResolve = new EpcToResolve();

                        string epcBase = "3410402AEA0000000000";
                        int baseDec = Convert.ToInt32("1000", 16);

                        // Creating the input of epc's baed on the ResolveBatchSize and number epcs's that needs to be resolved at xpress
                        string[] epcs = new string[1];
                        for (int i = 0; i < 1; i++)
                        {
                            int epcDec = baseDec + i;
                            epcs[i] = epcBase + epcDec.ToString("X");
                        }

                        // setting the epc list which is the input that is sent to xpress
                        epcToResolve.epcList = epcs;

                        //pass the flag to check if say whether the productInformation or just the product_id is resolved
                        epcToResolve.returnOnlyProductId = false;

                        //return productResolveService.getResolvedEpcs(epcToResolve);
                        productResolveService.getResolvedEpcs(epcToResolve);
                        this.BeginInvoke((Action)delegate { lstbxStatusMsgs.Items.Add("Resolved"); lstbxStatusMsgs.SelectedIndex = lstbxStatusMsgs.Items.Count - 1; });
                    }
                    catch (SoapHeaderException)
                    {
                        // do nothing
                    }
                    catch (SoapException se)
                    {
                        this.BeginInvoke((Action)delegate { lstbxStatusMsgs.Items.Add("Problem resolving products at xpress"); lstbxStatusMsgs.SelectedIndex = lstbxStatusMsgs.Items.Count - 1; });
                    }
                    catch (WebException we)
                    {
                        // get the reason for the exception
                        WebExceptionStatus status = we.Status;
                        String description = we.Message;

                        WebResponse response = we.Response;
                        if (response != null)
                        {
                            Stream respStream = response.GetResponseStream();

                            if (respStream != null)
                            {
                                respStream.Close();
                                respStream.Dispose();
                                respStream = null;
                            }
                            // close the response
                            response.Close();
                            response = null;
                        }
                        // Case when there is no connectivity. Just display an error message to the user to indicate that there is no connectivity.
                        this.BeginInvoke((Action)delegate { lstbxStatusMsgs.Items.Add("Resolve Product: There is no connectivity to xpress"); lstbxStatusMsgs.SelectedIndex = lstbxStatusMsgs.Items.Count - 1; });
                    }
                    catch (ThreadAbortException)
                    {
                        // Do nothing. Do not log
                    }
                    catch (System.Exception e)
                    {
                        this.BeginInvoke((Action)delegate { lstbxStatusMsgs.Items.Add("An exception occured when fetching data from xpress"); lstbxStatusMsgs.SelectedIndex = lstbxStatusMsgs.Items.Count - 1; });
                    }

                    try
                    {
                        Thread.Sleep(200);
                    }
                    catch
                    {
                    }
                }
            }

            resolving = false;
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            if (resolveThread != null && resolving)
            {
                resolveThread.Abort();
                resolveThread.Join();
                resolveThread = null;
                resolving = false;

                this.BeginInvoke((Action)delegate { lstbxStatusMsgs.Items.Add("Resolve Product: Stopped Thread"); lstbxStatusMsgs.SelectedIndex = lstbxStatusMsgs.Items.Count - 1; });
            }
        }
    }
}

On clicking on the Start Button in the form, the thread is created and keeping calling the webservice, when the stop is called, the thread is stopped. Repeated start and stop causes the ObjectDisposedException (that is how I reproduced this exception).

Any help on this regard will be highly appreciated, as I have been trying to solve this issue for a few days now.

Thanks Senthil

Senthil
  • 31
  • 3
  • Have you identified exactly where the error is coming from in your code? Is it from the call to getResolvedEpcs because the message is being disposed before it can be accessed? Is there any more to that stack trace, or is there an inner exception on the error? – Nanhydrin May 29 '12 at 10:14
  • This is from the .NET code and not from my code. The explanation that I have so far is that I should not reuse the stub (ProductResolveService), I need to close the request stream and the response stream everytime. If this is not done, then there is a Timer (for asynchronous calls) that wakes up and tries to access the request/response stream (I donot know which one) and finds it already disposed and hence throws this exception. The calls that I make are synchronous and I do not know why the Timer is still being used. – Senthil May 29 '12 at 10:29
  • Does the error only happen after you've hit stop or does it just happen randomly? – Nanhydrin May 29 '12 at 11:08
  • It seems to happen when I hit Stop and happens at random times. – Senthil May 29 '12 at 11:19
  • Ok. What I do is, I click on Start, it starts resolving, then I click on Stop and start it stops and starts to resolve. But if I do it fast enough to stop and start then the resolving does not happen. It times out and is never able to talk to the server. Now I hit stop and wait for few mins, so that all the resources are released (?) and then hit start, it works again. Now, I should do a start and stop, it will throw this exception. – Senthil May 29 '12 at 11:21
  • Should there perhaps be some cleanup in the catch for the ThreadAbortException? Closing streams or something like that similar to you're doing for the WebException? Have you tried running it in Debug and setting the exceptions to break whenever the ObjectDisposedException is thrown rather than just when it's unhandled? – Nanhydrin May 29 '12 at 12:09
  • Only WebException gives access to Response Stream and so we can clean it up. I had tried debug but without catching ODE. I will try catching it and see what happens. – Senthil May 29 '12 at 12:29
  • Did you ever get any further on this? I am facing the same issue. – Nik May 12 '14 at 16:20

1 Answers1

1

This is a pretty old post. However, I wanted to record my answer here for any body who is still looking for an answer.

Two options:

  1. Move to WCF Clients which is much easier and cleaner.
  2. Use the below solution.

    public class ExtendedDataImport : DataImport.DataImport
    {
        private WebRequest webRequest;
        private WebResponse webResponse;
    
        /// <summary>
        /// This method overrides the generated method and sets parameters so that HTTP 1.0
        /// is used (without chunking). If left with default parameters it
        /// sometimes fails.
        /// </summary>
        protected override WebRequest GetWebRequest(Uri uri)
        {
            webRequest = base.GetWebRequest(uri);
            ((HttpWebRequest)webRequest).KeepAlive = false;
            ((HttpWebRequest)webRequest).ProtocolVersion = HttpVersion.Version10;
            return webRequest;
        }
    
        protected override WebResponse GetWebResponse(WebRequest request)
        {
            webResponse = base.GetWebResponse(request);
            return webResponse;
        }
    
        public void Close()
        {
            if (webResponse != null)
            {
                Stream responseStream = webResponse.GetResponseStream();
                responseStream.Close();
                responseStream.Dispose();
                responseStream = null;
                webResponse.Close();
                webResponse = null;
            }
    
            if (webRequest != null)
            {
                // Aborting the WebRequest, cleans up the webrequest and
                // stops the timer which causes the ObjectDisposedException
                try
                {
                    webRequest.Abort();
                    webRequest = null;
                }
                catch (ObjectDisposedException ex)
                {
                    // Ignoring the object disposed exception as mentioned in the follwoing link
                    //http://social.msdn.microsoft.com/Forums/en/netfxcompact/thread/8f21514c-9b7c-40d3-96c9-794c0dc167fe
                }
            }
        }
    
        protected override void Dispose(bool disposing)
        {
            Close();
            base.Dispose(disposing);
        }
    }
    
Senthil
  • 31
  • 3