.NET CF WebService ObjectDisposedException

Я пытаюсь решить проблему с одним из моих проектов Smart Device (.NET CF 3.5 на устройстве Windows Mobile 6.5).

Код пытается постоянно совершать вызовы веб-сервиса, чтобы получить некоторые данные и использовать их в форме. Во время использования для конкретного случая возникает исключение ObjectDisposedException, и приложение аварийно завершает работу. Трассировка стека

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()

Я прочитал много блогов и форумов, в том числе этот, и предлагаемое решение, по-видимому, состоит в том, чтобы закрыть поток запросов и запрос до получения ответа.

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

Но это не спасает мою ситуацию. Если requestStream закрывается перед записью данных в поток, то он ничего не делает. Если я закрою после получения ответа, он выдаст InvalidOperationException.

Ниже приведен мой код:

Ссылка.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; });
            }
        }
    }
}

При нажатии кнопки «Пуск» в форме поток создается и продолжает вызывать веб-службу, когда вызывается остановка, поток останавливается. Повторный запуск и остановка вызывают ObjectDisposedException (именно так я воспроизвел это исключение).

Любая помощь в этом отношении будет высоко оценена, так как я пытаюсь решить эту проблему уже несколько дней.

Спасибо Сентил


comment
Вы точно определили, откуда возникает ошибка в вашем коде? Это из-за вызова getResolvedEpcs, потому что сообщение удаляется до того, как к нему можно будет получить доступ? Есть ли что-то еще в этой трассировке стека или есть внутреннее исключение ошибки?   -  person Nanhydrin    schedule 29.05.2012
comment
Это из кода .NET, а не из моего кода. Объяснение, которое у меня есть до сих пор, заключается в том, что я не должен повторно использовать заглушку (ProductResolveService), мне нужно каждый раз закрывать поток запросов и поток ответов. Если этого не сделать, то есть таймер (для асинхронных вызовов), который просыпается и пытается получить доступ к потоку запроса/ответа (я не знаю, какой именно) и находит его уже утилизированным и, следовательно, выдает это исключение. Вызовы, которые я делаю, синхронны, и я не знаю, почему Таймер все еще используется.   -  person Senthil    schedule 29.05.2012
comment
Ошибка возникает только после того, как вы нажмете «Стоп», или это происходит случайно?   -  person Nanhydrin    schedule 29.05.2012
comment
Кажется, это происходит, когда я нажимаю «Стоп», и происходит в случайное время.   -  person Senthil    schedule 29.05.2012
comment
Ok. Что я делаю, я нажимаю «Пуск», он начинает разрешаться, затем я нажимаю «Стоп» и запускаю, он останавливается и начинает разрешаться. Но если я делаю это достаточно быстро, чтобы остановиться и начать, то разрешения не происходит. Время ожидания истекло, и он никогда не сможет связаться с сервером. Теперь я нажимаю «Стоп» и жду несколько минут, чтобы все ресурсы были освобождены (?), а затем нажимаю «Пуск», все снова работает. Теперь я должен запустить и остановить, это вызовет это исключение.   -  person Senthil    schedule 29.05.2012
comment
Возможно, должна быть какая-то очистка в улове для ThreadAbortException? Закрытие потоков или что-то подобное тому, что вы делаете для WebException? Вы пытались запустить его в Debug и настроить исключения на прерывание всякий раз, когда возникает ObjectDisposedException, а не только тогда, когда оно необработано?   -  person Nanhydrin    schedule 29.05.2012
comment
Только WebException дает доступ к Response Stream, поэтому мы можем его очистить. Я пробовал отлаживать, но не поймал ODE. Я попробую поймать его и посмотреть, что произойдет.   -  person Senthil    schedule 29.05.2012
comment
Вы когда-нибудь продвинулись дальше в этом? Я столкнулся с той же проблемой.   -  person Nik    schedule 12.05.2014


Ответы (1)


Это довольно старый пост. Тем не менее, я хотел записать свой ответ здесь для всех, кто все еще ищет ответ.

Два варианта:

  1. Перейдите на клиенты WCF, которые намного проще и чище.
  2. Используйте приведенное ниже решение.

    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);
        }
    }
    
person Senthil    schedule 25.01.2017