.NET CF WebService ObjectDisposedException
Я пытаюсь решить проблему с одним из моих проектов для смарт-устройств (.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.
Ниже приведен мой код:
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; });
}
}
}
}
При нажатии на кнопку "Пуск" в форме поток создается и продолжает вызывать веб-сервис. Когда вызывается остановка, поток останавливается. Повторный запуск и остановка вызывает исключение ObjectDisposedException (именно так я воспроизвел это исключение).
Любая помощь в этом отношении будет высоко оценена, так как я пытаюсь решить эту проблему в течение нескольких дней.
Спасибо сентил
1 ответ
Это довольно старый пост. Тем не менее, я хотел записать свой ответ здесь для любого органа, который все еще ищет ответ.
Два варианта:
- Перейдите к клиентам WCF, что намного проще и чище.
Используйте приведенное ниже решение.
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); } }