object disposed exception - c#

Ok guys there is this sudden problem in my code which didn't appear before..
public void StartUdpListener(Object state)
{
/* sock1 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sock1.Bind(receiveEndPoint);
EndPoint ep = (EndPoint)receiveEndPoint;*/
recv = sock1.ReceiveFrom(receivedNotification, ref ep);
notificationReceived = Encoding.ASCII.GetString(receivedNotification, 0, recv);
//sock1.Close();
if (listBox1.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate { listBox = new StringBuilder(this.listBox1.Text); });
}
listBox.AppendLine(notificationReceived);
if (listBox1.InvokeRequired)
{
pos = listBox1.FindString(notificationReceived);
if (pos >= 0)
{
}
else
{
this.Invoke((MethodInvoker)delegate { this.listBox1.Items.Add(listBox.ToString()); });
}
}
}
I am getting an ObjectDisposedException saying that the line:
this.Invoke((MethodInvoker)delegate { listBox = new StringBuilder(this.listBox1.Text); });
cannot be executed since listBox1 is disposed.How is that possible and is there anything that needs to be done?

I am making the following assumptions:
This code is a method in a Form (System.Windows.Forms.Form).
The variable 'listBox1' is a ListBox control on the form.
You are receiving the ObjectDisposedException when the form is closed.
You are running this method on a separate thread (not shown in the code, but implied by the question).
I would guess that your code is blocking on the receiveFrom() call on the socket when the form is closed. The next message that arrives from the network causes receiveFrom to return, after which you put the message received into a listbox that no longer exists. The first time you access this listbox is code line "this.listBox1.Text" when creating the StringBuilder, which is the line that raises the ObjectDisposeException. The listBox is the object that is likely disposed, although it could also be the Form at this point, depening on how fast messages are coming in.
There appears to be plenty that needs to be done, but I am not sure what is proper advice. I would first validate my assumptions 1-4 above, then look into refactoring your application such that it does NOT use multiple threads. I make this suggestion because I must assume this is not the only "threading" issue your application may have. I certaintly may be incorrect in that assumption, in which case you can ignore the answer.
If I restrict the "what needs to be done" part of your question to a more limited scope, then I would advise to properly shutdown your UDP receiver before allowing the window to close, again assuming my assumptions are correct.

A comment on this block:
if (listBox1.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate { listBox = new
StringBuilder(this.listBox1.Text); });
}
listBox.AppendLine(notificationReceived);
The StringBuilder (listbox) may be null at the point you do .AppendLine. This is because you are creating the listbox in a different thread to where you using it. Also a new StringBuilder object only gets created if this code is run on a non UI thread (thats what listBox1.InvokeRequired) is checking.

Related

Socket.EndAccept throwing ArgumentException

Using .NET 6.0.
I called BeginAccept like so:
AsyncCallback callback = new AsyncCallback(AcceptCallback);
object? state = this.listenSocket;
_ = this.listenSocket.BeginAccept(callback, state);
and my AcceptCallback method gets called as expected. I then have to call EndAccept to obtain the receive socket:
private static void AcceptCallback(IAsyncResult result)
{
Socket? listenSocket = result.AsyncState as Socket;
if (listenSocket == null)
{
// note: This is impossible but it helps getting the possible
// null reference warnings out of the way.
throw new ArgumentNullException(nameof(result.AsyncState), "The state object is null.");
}
Socket receiveSocket = listenSocket.EndAccept(
out byte[] buffer,
out int bytesRead,
result); // and here it blows up
The last call gives me a "System.ArgumentException: 'Value does not fall within the expected range. (Parameter 'asyncResult')'".
Apparently is has a problem with the last argument. It is not something I provide though, it is the result argument I get passed by the system which (according to the debugger) is a proper System.Threading.Tasks.TaskToApm.TaskAsyncResult. I am just following the examples I found.
I started out without the wrapping new AsyncCallback() in the call to BeginAccept because I did not understand what good it does (I would like to know though). I also initially had non-static methods. Because I had this problem I changed it to be more like the original examples but the same exception remains.
What is the problem and what can I do to overcome it?
[Edit]
As pointed out by Hans Passant the result argument should not be a System.Threading.Tasks.TaskToApm.TaskAsyncResult and this causes the error. There is little talk or documentation about TaskAsyncResult on the internet which made me suspicious, thinking it could be a bug in new framework code. So I rebuild with .NET 5.0 but the result was the same.
I am just using System.Net.Sockets.Socket classes, nothing fancy from a custom library or anything like that.
It appears this first bit:
AsyncCallback callback = new AsyncCallback(AcceptCallback);
object? state = this.listenSocket;
_ = this.listenSocket.BeginAccept(callback, state);
makes it fail. If I change it to:
int maxSize = 0x2000; // 8K
AsyncCallback callback = new AsyncCallback(AcceptCallback);
object? state = this.listenSocket;
_ = this.listenSocket.BeginAccept(maxSize, callback, state);
it succeeds, no exception anymore on EndAccept and I get the expected data in my ReceiveCallback (the next step in the asynchronous flow).
Because I was new to socket programming I figured it would be wise to start simple so I used the BeginAccept overload with the least parameters. I assumed it would use a default for maximum size. Well, whatever that "simple" overload does, it is not good.
So the type System.Threading.Tasks.TaskToApm.TaskAsyncResult for the result argument of AcceptCallback is perfectly fine, no problem there (I checked, it is still the same).
I can proceed now.

(C#/UWP) Replacing UdpClient code with DatagramSocket

I'm mostly a C++ programmer looking to port some code over to C# but unfortunately developing for the hololens has forced me to use UWP. The following code has been working just fine for receiving some very fast UDP broadcasts (~250-500 per second)
while ( listener.Available > 0 )
{
byte[] bytes = listener.Receive(ref groupEP);
position = BitConverter.ToSingle(bytes, 0);
}
and as far as the "getting it to work" stage it's done. But moving over to UWP I'm apparently no longer allowed to use UdpClient and now forced to use "DatagramSocket" which has an async callback rather than giving you control of when you check for/process your data. I'm not generally against a callback vs playing catchup each update loop but the DatagramSocket doing roughly the same thing is causing flickering in rendering and generally just not working at all. I've tried about a thousand different ways of re-organizing my callback, but currently it looks like this:
async void MessageReceived(DatagramSocket socket, DatagramSocketMessageReceivedEventArgs eventArguments)
{
try
{
lock (this)
{
DataReader broadcastReader = eventArguments.GetDataReader();
asyncPosition = broadcastReader.ReadSingle();
}
}
catch (Exception exception)
{
}
}
I then in my update loop have this at the end, and position is used in my render routine
lock (this)
{
position = asyncPosition;
}
No matter what I put anywhere in the program or how I try and organize the callback and the variables used I can't seem to find any way to get this to work properly, and I'd really appreciate a primer on how to properly handle a DatagramSocket

Writing to textbox inside an unselected tab

I have a program that can read and write on serial, GPIB, USB, and Ethernet. It has a tab for each method of communication with a textbox inside that displays communication on the port. One of the tabs is listed as All Comms and that text box has data from all communication methods. I am currently working on the serial port portion of the code and my program keeps freezing. Half the time I run my code it functions without issue writing to both tabs. The other half it freezes up when it tries to write to the text box inside the tab that is not selected(found by stepping through the code a line at a time).
I pulled the text boxes outside the tab control and this fixes the freezing issue. When the program freezes it does not display an error message and does not crash so no crash report(left it running over the weekend and it never finished crashing).
I would think that I need to select the other tab and then write to it, but why would the code work correctly half the time I run it?
Image of the program
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
rxString = rxString + serialPort1.ReadExisting();
if (rxString == "\b")
{
//Removes 1 character when backspace is the key pressed
rxSerialTextBox.ReadOnly = false;
rxSerialTextBox.Select(rxSerialTextBox.TextLength - 1, rxSerialTextBox.TextLength);
rxSerialTextBox.SelectedText = String.Empty;
rxSerialTextBox.ReadOnly = true;
rxString = "";
}
while (rxString.Length != 0)
{
try
{
while (rxString.Length != 0)
{
if (rxString.IndexOf("\r\n") == 0)
{
//Adds a newline when newline is the next characters in the string
rxString = rxString.Substring(rxString.IndexOf("\r\n") + 2);
rxAllCommsTextBox.AppendText(Environment.NewLine);
rxSerialTextBox.AppendText(Environment.NewLine);
}
//Adds a new character to the text box
rxAllCommsTextBox.AppendText(rxString.Substring(0, 1));
rxSerialTextBox.AppendText(rxString.Substring(0, 1));
rxString = rxString.Substring(1, rxString.Length - 1);
}
}
catch
{
//rxString = "";
}
}
}
A quck look at the SerialPort.DataReceived event documentation brings into attention the following Remarks section paragraph:
The DataReceived event is raised on a secondary thread when data is received from the SerialPort object. Because this event is raised on a secondary thread, and not the main thread, attempting to modify some elements in the main thread, such as UI elements, could raise a threading exception. If it is necessary to modify elements in the main Form or Control, post change requests back using Invoke, which will do the work on the proper thread.
According to this, your code that touches UI elements (text boxes) inside that event handler is incorrect. What the documentation doesn't say is that when you do so, the behavior is undefined - sometimes it may work, another time hang, yet another time throw exception.
So, instead of asking why your incorrect code sometimes work, you'd better concentrate on making it correct, and only then if something is not working, ask why and seek for a solution.
P.S. I'm not going to address how the concrete issue can be solved - there are a tons of posts, explanations and examples of how to marshal the calls to the UI thread, and in that regard there is nothing special in your case.
It was a little confusing your question ...
you can try, it is understood correctly, try to keep the value you want to assign the memory context, and assign the value based on another type of iteration.
At the moment the application freezes, which shows the breakpoint? The expected behavior does it work?
I would try a configuration object, such as a list, with various configurations, and certain state, the amount you need to pass the list to the tabcontrol. Obviously, it needs to check what's not working and why is not ...

Socket ReceiveAsync reuse SocketAsyncEventArgs

I have a network equipment to which I connect once using sockets, and the connection is maintained open all the time until application closes.
Now I have a class in C# that encapsulates the communication. There is a method SendMessage to the equipment. I need to use Socket.ReceiveAsync to get the response.
Let's say there are 3 methods: 1. GetEqValA(), GetEqValB(), GetEqValC() that call SendMessage with a specific message for the equipment.
I have created only one instance of socket Event args like that:
_completeArgs = new SocketAsyncEventArgs();
_completeArgs.SetBuffer(buffer, 0, buffer.Length);
_completeArgs.UserToken = _mySocket;
_completeArgs.RemoteEndPoint = _mySocket.RemoteEndPoint;
_completeArgs.Completed += new EventHandler<SocketAsyncEventArgs>(DataAvailable);
_mySocket.ReceiveAsync(_completeArgs);
Now, the DataAvailable method has something similar to the code below:
for (int i = 0; i < e.BytesTransferred; i++)
{
_tcpData.Add(e.Buffer[i]);
}
if (_tcpData.Count == _expectedTcpDataCount)
{
_expectedTcpDataCount = -1;
ProcessData();
// I don't want to put here, because it will wait for data until
// someone sends a message and the equipment responds with data
//_mySocket.ReceiveAsync(e);
}
else
{
_mySocket.ReceiveAsync(e);
}
Now, the 3 methods from above can be called by anyone, even different threads. I do have a lock mechanism for that.
My problem is that if I reuse _completeArgs in SendMessage for the next message to send, I get an exception that this eventArgs object is already in use by an asynchronous operation, whereas if I do the same(but not directly, by taking the SocketAsyncEventArgs e parameter from DataAvailable) in DataAvailable, no problem occurs.
_mySocket.ReceiveAsync(_completeArgs);
_mySocket.Send(pMessage);
The idea is that I don't want to call ReceiveAsync all the time, even if I know that nothing will come in there, but I want to call ReceiveAsync before sending any message to the device, because I know that I will get something.
The exception appears at method GetEqValC(), if I call them one after another in the sequence A,B,C.
What I don't understand, can you help me? Can I don what I want to do?
I use .NET 3.5.
P.S. Summary: I need to keep the connection alive, but read something from it only when I know for sure I must have something in there. Only one call at a time will be. One send, followed by one receive!

Terminating a Form while COM DataReceived Event keeps fireing. C#

I'm currently having a problem, which seems to be related to closing a Form, while a scale, which is connected through a Serial Connection keeps sending data (about 3 packages per sek).
I handle new data over the DataReceived-Event (handling itself might be uninteresting for this issue, since I'm just matching data) Keep an eye on the COM_InUse variable and the allowFireDataReceived check.):
private void COMScale_DataReceived(object sender, EventArgs e)
{
if (allowFireDataReceived)
{
//set atomar state
COM_InUse = true;
//new scale:
if (Properties.Settings.Default.ScaleId == 1)
{
strLine = COMScale.ReadTo(((char)0x2).ToString());
//new scale:
Regex reg = new Regex(Constants.regexScale2);
Match m = reg.Match(strLine);
if (m.Success)
{
strGewicht = m.Groups[1].Value + m.Groups[2];
double dblComWeight;
double.TryParse(strGewicht, out dblComWeight);
dblScaleActiveWeight = dblComWeight / 10000;
//add comma separator and remove zeros
strGewicht = strGewicht.Substring(0, 1) + strGewicht.Substring(1, 2).TrimStart('0') + strGewicht.Substring(3);
strGewicht = strGewicht.Insert(strGewicht.Length - 4, ",");
//write to textbox
ThreadSafeSetActiveScaleText(strGewicht);
COMScale.DiscardInBuffer();
//MessageBox.Show(dblScaleActiveWeight.ToString(), "dblScaleActiveWeight");
}
}
//free atomar state
COM_InUse = false;
}
}
The COM_InUse variable is a global bool and "tells" if there is a current process of handling data.
The allowFireDataReceived is also a global bool and if set to false will lead to no extra handling of the data which has been sended.
My problem now is the following:
It seems that Eventhandling is a separate Thread, which leads to a deadlock on klicking the Cancel-Button since the COM_InUse will never turn to false, even if the Event was handled (see end of COMScale_DataReceived, where COM_InUse is set to false).
While setting allowFireDataReceived = false works perfectly (no handling any more), as I said: the while loop will not terminate.
private void bScaleCancel_Click(object sender, EventArgs e)
{
allowFireDataReceived = false;
while (COM_InUse)
{
;
}
if (!COM_InUse)
{
ret = 1;
SaveClose();
}
}
When I comment out the while-block I have to click twice on the button, but it works without a crash. Since this very user unfriendly, I'm searching for an alternative way to safely close the window.
Info:
Simply closing (without checking if the COM-Data was processed) lead to a fatal crash.
So, maybe someone can explain to me what exactly causes this problem or can provide a solution to this. (Maybe one would be to trigger the Cancel-Clicking Event again, but that is very ugly)
Greetings!
I count on you :)
//edit:
Here is the current code of
private void ThreadSafeSetActiveScaleText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.lScaleActive.InvokeRequired)
{
SafeActiveScaleTextCallback d = new SafeActiveScaleTextCallback(ThreadSafeSetActiveScaleText);
this.Invoke(d, new object[] { text });
}
else
{
this.lScaleActive.Text = text;
}
}
ThreadSafeSetActiveScaleText(strGewicht);
Yes, the DataReceived event runs on a threadpool thread. You already knew that, you wouldn't have called it "ThreadSafe" otherwise. What we can't see is what is inside this method. But given the outcome, it is highly likely that you are using Control.Invoke().
Which is going to cause deadlock when you loop on COM_InUse in code that runs on the UI thread. The Control.Invoke() method can only complete when the UI thread has executed the delegate target method. But the UI thread can only do that when it is idle, pumping the message loop and waiting for Windows messages. And invoke requests. It cannot do this while it looping inside the Click event handler. So Invoke() cannot complete. Which leaves the COM_InUse variable for ever set to true. Which leaves the Click event handler forever looping. Deadlock city.
The exact same problem occurs when you call the SerialPort.Close() method, the port can only be closed when all events have been processed.
You will need to fix this by using Control.BeginInvoke() instead. Make sure the data is still valid by the time the delegate target starts executing. Pass it as an argument for example, copying if necessary.
Closing the form while the scale is unrelentingly sending data is in general a problem. You'll get an exception when you invoke on a disposed form. To fix this, you'll need to implement the FormClosing event handler and set e.Cancel to true. And unsubscribe the DataReceived event and start a timer. Make the Interval a couple of seconds. When the timer Ticks, you can close the form again, now being sure that all data was drained and no more invokes can occur.
Also note that calling DiscardInBuffer() is only good to randomly lose data.

Categories

Resources