2

J'essaie de résoudre un problème avec l'un de mes projets Smart Device (.NET CF 3.5 sur Windows Mobile 6.5 Device)..NET WebService Web ObjectDisposedException

Le code tente d'effectuer des appels de service Web en continu pour obtenir des données et les utiliser dans le formulaire. Lors de l'utilisation, pour un cas particulier, une ObjectDisposedException est levée et l'application se bloque. Le stacktrace est

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

J'ai lu de nombreux blogs et forums, y compris cela, et la solution proposée semble être de fermer le flux de demande et la demande, avant d'obtenir la réponse.

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

Mais cela n'aide pas ma situation. Si le requestStream est fermé avant d'écrire dans les données du flux, il ne fait rien. Si je ferme après avoir reçu la réponse, il lève InvalidOperationException.

Après mon 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; }); 
      } 
     } 
    } 
} 

En cliquant sur le bouton Démarrer sous la forme, le fil est créé et maintenir l'appel le webservice, quand l'arrêt est appelé, le thread est arrêté. Le démarrage et l'arrêt répétés provoquent le ObjectDisposedException (c'est ainsi que j'ai reproduit cette exception).

Toute aide à cet égard sera grandement appréciée, car j'ai essayé de résoudre ce problème depuis quelques jours maintenant.

Merci Senthil

+0

Avez-vous identifié exactement où l'erreur vient dans votre code? Est-ce à partir de l'appel à getResolvedEpcs parce que le message est éliminé avant d'être accessible? Y a-t-il d'autres traces dans cette pile ou y a-t-il une exception interne dans l'erreur? – Nanhydrin

+0

Ceci provient du code .NET et non de mon code. L'explication que j'ai jusqu'à présent est que je ne devrais pas réutiliser le stub (ProductResolveService), j'ai besoin de fermer le flux de la requête et le flux de réponse à chaque fois. Si cela n'est pas fait, alors il y a un Timer (pour les appels asynchrones) qui se réveille et essaie d'accéder au flux de requête/réponse (je ne sais pas lequel) et le trouve déjà éliminé et jette donc cette exception. Les appels que je fais sont synchrones et je ne sais pas pourquoi le Timer est toujours utilisé. – Senthil

+0

L'erreur se produit-elle seulement après que vous avez frappé l'arrêt ou est-ce que cela se produit au hasard? – Nanhydrin

Répondre

1

C'est un joli ancien poste. Cependant, je voulais enregistrer ma réponse ici pour tout organisme qui cherche toujours une réponse.

Deux options:

  1. Déplacer aux clients WCF qui est beaucoup plus facile et plus propre.
  2. Utilisez la solution ci-dessous.

    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); 
        } 
    }