I have quite the problem here. I have an MVP application where I have a model that handles the implementation for talking to an external device. In the application I create 4 instances of this class. Each instance communicates to its external device via a UDP socket using a unique IP and port.
Now for all initial testing everything seemed fine as I have 4 views and each view shows a count for each device that is unique. For testing I always only connected to a single device and the other 3 connections were doing nothing, but there views always showed a count of zero as expected.
The problem came when I started programatically creating individual log4net loggers to log the count from each instance based upon a timer firing. What I found was that each log file was logging the same count! I thought it was my log4net implementation, but alas when debugging I saw for myself in the debugger each instance returning the same count.
When the instances of the models are created they are all passed to a presenter which holds a reference to each. Each model is given a unique string identifier which is how I know which instance I am viewing when debugging (aside from the IP and port).
Also, I should note that the counts are set on reception of a unsolicited UDP packet which never comes in on 3 of the instances.
My inheretince is as follows.
HeadModel
-HeadModelAbstract
–SubModel
—SubModelAbstract
The referenced count is in the SubModel. It was done this way because I need a class for talking to the base level device which has a set level of limited functionality. However more advanced devices will have that functionality plus additional functionality. I originally wanted to pass around interfaces but found that doing that would hide properties and methods in the SubModel which I still wanted to expose so I went with the abstract implementation you see.
Thank you to all who made it this far to try and help out.
SUMMARY – why are 4 unique instances of a class all returning the same value for the same non-static properties?
UPDATE: Here is the misc code
SystemStatus holds all the counts and state. The ParseSystemStatus function is called from an event handler that is triggered every time a UDP message is received.
public class SuccintClass : SuccintAbstract{
UdpServer udpServer = null;
public SuccintClass(int port){
udpServer = new UdpServer(port); //Start receiver on port 3000
udpServer.PacketReceived += client_UnsolicitedMessageReceived;
}
private void client_UnsolicitedMessageReceived(object sender, PacketReceivedEventArgs e) {
ushort msgID = (ushort)((e.Buffer.Data[10]<<8) + e.Buffer.Data[11]);
byte[] data = new byte[e.Buffer.Length];
Array.Copy(e.Buffer.Data, 0, data, 0, e.Buffer.Length);
switch (msgID) {
case 9001:
break;
case 0x5000:
break;
case 9005: //System Status
ParseSystemStatus(data);
OnSystemStatusReceived(new SystemStatusReceivedEventArgs(this.sysStatus));
break;
case 9014:
break;
default:
break;
}
}
private SystemStatus sysStatus = SystemStatus.NullStatus;
public void ParseSystemStatus(byte[] buffer) {
int CounterOffset = 14;
int[] converted = new int[6];
for (int i = 0; i < 6; i++) {
converted[i] = BitConverter.ToInt32(buffer, i * 4 + CounterOffset);
}
this.sysStatus.State = (SystemStatus.SystemState)converted[0];
this.sysStatus.Count1 = converted[1];
this.sysStatus.Count2= converted[2];
this.sysStatus.Count3= converted[3];
this.sysStatus.Count4= converted[4];
this.sysStatus.Count5= converted[5];
}
}
Then UdpServer looks like this
sealed class UdpServer : IDisposable {
public UdpServer( int serverPort ) {
this.socket = new Socket( AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );
this.socket.Bind( new IPEndPoint( IPAddress.Any, serverPort ) );
for ( int i = 0; i < 200; i++ ) {
BeginAsyncReceive( );
}
}
~UdpServer( ) {
Dispose( false );
}
public void Dispose( ) {
Dispose( true );
GC.SuppressFinalize( this );
}
private void Dispose( bool isDisposing ) {
if ( !disposed ) {
disposed = true;
rwLock.AcquireWriterLock( Timeout.Infinite );
socket.Close( );
rwLock.ReleaseWriterLock( );
while ( threads > 0 )
Thread.Sleep( 1 );
}
}
private bool disposed;
private void BeginAsyncReceive( ) {
rwLock.AcquireReaderLock( Timeout.Infinite );
UdpPacketBuffer buffer = UdpPacketBufferPool.GetInstance( ).GetFromPool( );
try {
socket.BeginReceiveFrom( buffer.Data, 0, buffer.Data.Length, SocketFlags.None, ref buffer.RemoteEndPoint, EndAsyncReceive, buffer );
Interlocked.Increment( ref threads );
}
catch ( SocketException exc ) {
if ( logger.IsWarnEnabled ) {
logger.Warn( "Error happened at the start of packet acquisition." );
logger.Warn( exc.ToString( ) );
}
}
catch ( ObjectDisposedException exc ) {
}
rwLock.ReleaseReaderLock( );
}
private void EndAsyncReceive( IAsyncResult asyncResult ) {
BeginAsyncReceive( );
rwLock.AcquireReaderLock( Timeout.Infinite );
UdpPacketBuffer buffer = (UdpPacketBuffer)asyncResult.AsyncState;
try {
buffer.Length = socket.EndReceiveFrom( asyncResult, ref buffer.RemoteEndPoint );
OnPacketReceived( new PacketReceivedEventArgs( buffer ) );
}
catch ( SocketException exc ) {
logger.Warn( "Error happened during completion of packet acquisition." );
logger.Warn( exc.Message );
logger.Warn( exc.StackTrace );
}
catch ( ObjectDisposedException ) {
}
Interlocked.Decrement( ref threads );
rwLock.ReleaseReaderLock( );
}
private void OnPacketReceived( PacketReceivedEventArgs args ) {
EventHandler<PacketReceivedEventArgs> handler = PacketReceived;
if ( handler != null ) {
handler( this, args );
}
}
public event EventHandler<PacketReceivedEventArgs> PacketReceived;
private int threads;
private ReaderWriterLock rwLock = new ReaderWriterLock( );
private Socket socket;
private ILog logger = LogManager.GetLogger( typeof( UdpServer ) );
}
And finally the counts are returned using getters and setters accessing the properties of the SystemStatus object
override public int Count1 {
get { return sysStatus.Count1; }
}
override public int Count2 {
get { return sysStatus.Count2 ; }
}
override public int Count3 {
get { return sysStatus.Count3 ; }
}
override public int Count4 {
get { return sysStatus.Count4 ; }
}
override public int Count5 {
get { return sysStatus.Count5 ; }
}
Each instance is started on its own unique port. I have put break points on the callback function for a unsolicited message received but never break for any instance other than the one that is actually meant to receive the data, yet all return the same counts.
When you initialize the sysStatus, you set it to SystemStatus.NullStatus, which I assume is a static SystemStatus instance. This assignment updates the sysStatus variable to point to the NullStatus object in memory – it does NOT make a copy of that object. When you set values through the sysStatus variable, it will update the same object pointed to by SystemStatus.NullSTatus, which is a static object shared by all instances. You may want to change this to a struct, or use a new SystemStatus() instead of pointing sysStatus to that static instance.
EDIT: Below was my original answer…
I suspect the key to your problem is here:
All 3 of your instances are wired up to listen for the PacketReceived event. When the OnPacketReceived method is called and it triggers the event stored in PacketReceived, that will fire off all of the event handlers which are wired up to listen to it. That means the client_UnsolicitedMessageReceived method will be called individually for each instance of your class.
In other words, the way your system is written now, you have 1 UDP server. Every time it receives a packet, it will notify every instance of SuccinctClass that the packet was received. If you want different behavior, you may have to come up with a way to specify which instance you really want to notify, or to detect from within an instance of SuccinctClass whether you really want to act on a particular packet or leave it up to another instance of the class.