.NET Framework Bookmark and Share   
 index > .NET Remoting and Runtime Serialization > How to check if object reference is null in remoting c#
 

How to check if object reference is null in remoting c#

How i know if if my reference points to a null object in .NET Remoting ?
Bruno Vellego

I read the Observer example you posted, and I made my own implementation of it.
So, it doesn't exactly match your IObserver structure, but it is very similar.

1) Create a blank solution. Create 3 projects: 1 console application called 'Service' , 1 console application called 'Library' and 1 class library called 'Library'

2) Add reference to Systen.Runtime.Remoting in Service and Client

3) Add reference to Library in Service and Client

4) Add 4 classes to Library: Observer, ConcreteObserver, Subject, ConcreteSubject

using System;
using System.Collections.Generic;
using System.Text;

namespace Library
{
public abstract class Observer : MarshalByRefObject
{
public abstract void Update();
}
}


using System;
using System.Collections.Generic;
using System.Text;

namespace Library
{
public class ConcreteObserver: Observer
{
private string _observerState;
private ConcreteSubject _subject;

// Constructor
public ConcreteObserver(ConcreteSubject subject)
{
this._subject = subject;
}

public override void Update()
{
_observerState = _subject.SubjectState;
Console.WriteLine("Observer's new state is {0}", _observerState);
}

// Gets or sets subject
public ConcreteSubject Subject
{
get { return _subject; }
set { _subject = value; }
}
}
}


using System;
using System.Collections.Generic;
using System.Runtime.Remoting;

namespace Library
{
public class Subject : MarshalByRefObject
{
private List<Observer> _observers = new List<Observer>();

public void Attach(Observer observer)
{
_observers.Add(observer);
}

public void Detach(Observer observer)
{
_observers.Remove(observer);
}

public void Notify()
{
for (int i = _observers.Count - 1; i >= 0; i--)
{
try
{
_observers[i].Update();
}
catch (System.Net.Sockets.SocketException)
{
_observers.RemoveAt(i);
Console.WriteLine("Client was removed");
}
}
}
}
}


using System;
using System.Collections.Generic;
using System.Text;

namespace Library
{
public class ConcreteSubject: Subject
{
private string _subjectState;

// Gets or sets subject state

public string SubjectState
{
get { return _subjectState; }
set { _subjectState = value; }
}

}
}


5) Add an app.config to the Service project

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown mode="Singleton" type="Library.ConcreteSubject, Library" objectUri="ConcreteSubject.rem" />
</service>
<channels>
<channel ref="tcp" port="8085">
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full" />
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>

6) Alter the program.cs for the Service project

using System;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Threading;

using Library;

namespace Service
{
class Program
{
private static ConcreteSubject _concreteSubject;

static void Main(string[] args)
{
try
{
RemotingConfiguration.Configure("Service.exe.config", false);
Console.WriteLine("Service is configured");

_concreteSubject = new ConcreteSubject();
RemotingServices.Marshal(_concreteSubject, "ConcreteSubject.rem", typeof(ConcreteSubject));

KeepNotifying();

// Wait for user
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.ReadLine();
}
}

private static void KeepNotifying()
{
while (true)
{
Thread.Sleep(2000);

_concreteSubject.SubjectState = "ABC";

Console.WriteLine("Notifying clients...");
_concreteSubject.Notify();
}
}
}
}

7) Create an app.config in the Client project

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown type="Library.ConcreteSubject, Library" url="tcp://localhost:8085/ConcreteSubject.rem" />
</client>
<channels>
<channel ref="tcp" port="0">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>

8) Alter the program.cs for the Client project

using System;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Threading;
using Library;

namespace Client
{
class Program
{
private static ConcreteObserver _observer;

static void Main(string[] args)
{
try
{
RemotingConfiguration.Configure("Client.exe.config", false);
Console.WriteLine("Client is configured");

Thread.Sleep(500);

ConcreteSubject s = new ConcreteSubject();

_observer = new ConcreteObserver(s);

s.Attach(_observer);

Console.ReadKey();

// By not detaching, an invalid state should occur.
// s.Detach(_observer);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.ReadLine();
}
}
}
}

9) Richt click solution - properties - set multiple startup projects - Set Client and Service to start

10) Run the program

Notice that the line s.Detach(_observer); has been put in comments
This means that the client does not properly clean up its registration.
So, if both programs are running, you see that the client is writing output, and the service tells when it is writing to clients.
Now shut down the client, but keep the server running
Notice that the console window says (at the next iteration) 'Client was removed' but at the same time, it keeps notifying other clients.

Now, uncomment the line s.Detach(_observer); and try the same procedureagain.
This time the client has unregistered itself and the server does not need to clean up.
You can see this because when you close the client (by pressingRETURN twice) there isNO line that says 'Client was removed'.

So, as a conclusion:
Whether or not the client cleans up after itself, it is always removed from the service if it is disconnected.

P.S. It appears you have to catch a SocketException instead of a RemotingException, so I was mistaken about that.

Hopefully this helps,
Kind regards,
Stefan

  • Marked As Answer byBruno Vellego Monday, September 21, 2009 12:56 PM
  •  
Stefan H.F. A.
So Subject is a remotable type inside which the Notify method is placed.

Is your Observer a remotable type also? if yes, have you registered it through another TCP channel seperately or what?

The reason of your problem could be that you're trying to remove an object from List while you're looping through it; no matter it's a remotable type or not you can't do that in C#.

use "for" instead of "foreach" and your problem may be fixed.

int count =_observers.Count;
for(int index = 0; index <count; index ++)
{

	try
                {
                    _observers[index].SendMessage(_publisherMessage);
                }
                catch (Exception err)
                {
                    _observers.RemoveAt(index);
		    index--; // because one item has been removed
}

}




  • Marked As Answer byBruno Vellego Monday, September 21, 2009 12:56 PM
  •  
Dynamic
more easy... how to detect a crashed/disconnected client from the server?
Bruno Vellego
You can try-catch your remote procedure call.
If the server is disconnected, a RemotingException will be thrown.
Stefan H.F. A.

Thanks for the help Stefan.

Itworks but i can´t discard the objects.

I'm using the Observer pattern over .NET Remoting puting the remote client objects in a List<> (myList.Add(remoteObject) ) ...
I can´tremove the Client referenceif the Client disconnect from Server without call myList.Remove(remoteObject) before.

It give-me the exception:

"An exception of type 'System.Net.Sockets.SocketException' occurred in mscorlib.dll and wasn't handled before a managed/native boundary

Additional information: No connection could be made because the target machine actively refused it"

Bruno Vellego

Ican thinkof2 possible ways of fixing this:

The nicest way would be to catch the RemotingException as I mentioned, and then check the exception's properties to determine if it's a connection failure.
If it is, you can call another method that will remove the object from the list.
Problem is, I don't know by heart which properties the RemotingException has.
Perhaps it has an ErrorCode or Hresult or something similar that you can check?


Another option would be tocreate a new remote method called TestConnection() on the remotable type.
The method would look like this:

public void TestConnection()
{ }

You could execute TestConnection in the catch-part
But if execution of the TestConnection fails, you could concider it a connection failure (it cannot be a business failure since there is no logic).
In that case, you couldremove it from the list, like in the previous method

Stefan H.F. A.

Thanks again Stefan and Sorryabout my english...

I´m trying this:

        private List<IObserver> _observers = new List<IObserver>();

        public void Notify()
        {
            foreach (IObserver observer in _observers)
            {
                try
                {
                    observer.SendMessage(_publisherMessage);
                }
                catch (Exception err)
                {
                    _observers.Remove(observer);
                }
            }
        }


But when i call _observers.Remove(observer); the server crashes and give-me the message:

"An exception of type 'System.Net.Sockets.SocketException' occurred in mscorlib.dll and wasn't handled before a managed/native boundary

Additional information: No connection could be made because the target machine actively refused it"

Bruno Vellego
Whichare theremotable types?
Is the IObserver the remotable type?
Or the class that contains the Notify() Method?
or both?

It seems illogical to me that the _observer.Remove method would cause this exception.
After all, the _observers variablehas already been referenced in the foreach statement without crashing.
So, if you're able to enumerate _observers, you should also be able to call Remove on it.

Can you verify if the exception occurs immediately when calling the Notify method, or when calling the observer.SendMessage method?
You could set a breakpoint on the Notify method and see where it crashes.

Stefan H.F. A.
I´m using this example: http://www.dofactory.com/Patterns/PatternObserver.aspx replacing the name Investor and IInvestor to Observer and IObserver.

The remotable type is a class that implements IObserver interface (like the Investor class in the site example) and i replace the method "Update" of the example to "SensMessage"

The _publisherMessage is a string.

The exception occurs when i callobserver.SendMessage(_publisherMessage); becouse the observer is disconnected...

Exception msg:

" The write operation failed, see inner exception.
An existing connection was forcibly closed by the remote host
No connection could be made because the target machine actively refused it <IP NUMBER> "

Then iwant to remove this observer object from List... and i call _observers.Remove(observer); and it give-me the message:

"An exception of type 'System.Net.Sockets.SocketException' occurred in mscorlib.dll and wasn't handled before a managed/native boundary

Additional information: No connection could be made because the target machine actively refused it"

Bruno Vellego

I see that there are 4 types:

Subject
ConcreteSubject
Observer (I guess you called this IObserver)
ConcreteObserver (I guess you called this Observer)

Could you tell me which are being remoted and how?
That is, are they SAO singleton, SAO singlecall or CAO ?

Stefan H.F. A.
On the server side i have:

            BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();

            provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

            IDictionary props = new Hashtable();

            props["port"] = 8085;
            props["socketCacheTimeout"] = "10000";

            TcpChannel chan1 = new TcpChannel(props,null,provider);

            ChannelServices.RegisterChannel(chan1,true);

            RemotingConfiguration.RegisterWellKnownServiceType(typeof(Subject), "Subject", WellKnownObjectMode.Singleton);

            mySubject = new Subject();



<br/>
On the client side i have:
                TcpChannel _chan = new TcpChannel(props, null, provider);

                ChannelServices.RegisterChannel(_chan, true);

                connstring = "tcp://" + ip + ":" + port + "/Subject";

                _mySubjectRef = (Subject)Activator.GetObject(typeof(Subject),connstring );






Subject are SAO singleton.

This model works fine... the problems is when a client crashes and haven't chance to call remove.(Observer) before crashes... the server keep a reference of a disconnected client
Bruno Vellego
So Subject is a remotable type inside which the Notify method is placed.

Is your Observer a remotable type also? if yes, have you registered it through another TCP channel seperately or what?

The reason of your problem could be that you're trying to remove an object from List while you're looping through it; no matter it's a remotable type or not you can't do that in C#.

use "for" instead of "foreach" and your problem may be fixed.

int count =_observers.Count;
for(int index = 0; index <count; index ++)
{

	try
                {
                    _observers[index].SendMessage(_publisherMessage);
                }
                catch (Exception err)
                {
                    _observers.RemoveAt(index);
		    index--; // because one item has been removed
}

}




  • Marked As Answer byBruno Vellego Monday, September 21, 2009 12:56 PM
  •  
Dynamic
That iscertainly right, but it still doesn't explain why he gets a Socket exception.
If you remove an item within a foreach, you'd get an InvalidOperationException, not a SocketException.
So, there must be something else that is wrong also.
Stefan H.F. A.

I read the Observer example you posted, and I made my own implementation of it.
So, it doesn't exactly match your IObserver structure, but it is very similar.

1) Create a blank solution. Create 3 projects: 1 console application called 'Service' , 1 console application called 'Library' and 1 class library called 'Library'

2) Add reference to Systen.Runtime.Remoting in Service and Client

3) Add reference to Library in Service and Client

4) Add 4 classes to Library: Observer, ConcreteObserver, Subject, ConcreteSubject

using System;
using System.Collections.Generic;
using System.Text;

namespace Library
{
public abstract class Observer : MarshalByRefObject
{
public abstract void Update();
}
}


using System;
using System.Collections.Generic;
using System.Text;

namespace Library
{
public class ConcreteObserver: Observer
{
private string _observerState;
private ConcreteSubject _subject;

// Constructor
public ConcreteObserver(ConcreteSubject subject)
{
this._subject = subject;
}

public override void Update()
{
_observerState = _subject.SubjectState;
Console.WriteLine("Observer's new state is {0}", _observerState);
}

// Gets or sets subject
public ConcreteSubject Subject
{
get { return _subject; }
set { _subject = value; }
}
}
}


using System;
using System.Collections.Generic;
using System.Runtime.Remoting;

namespace Library
{
public class Subject : MarshalByRefObject
{
private List<Observer> _observers = new List<Observer>();

public void Attach(Observer observer)
{
_observers.Add(observer);
}

public void Detach(Observer observer)
{
_observers.Remove(observer);
}

public void Notify()
{
for (int i = _observers.Count - 1; i >= 0; i--)
{
try
{
_observers[i].Update();
}
catch (System.Net.Sockets.SocketException)
{
_observers.RemoveAt(i);
Console.WriteLine("Client was removed");
}
}
}
}
}


using System;
using System.Collections.Generic;
using System.Text;

namespace Library
{
public class ConcreteSubject: Subject
{
private string _subjectState;

// Gets or sets subject state

public string SubjectState
{
get { return _subjectState; }
set { _subjectState = value; }
}

}
}


5) Add an app.config to the Service project

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown mode="Singleton" type="Library.ConcreteSubject, Library" objectUri="ConcreteSubject.rem" />
</service>
<channels>
<channel ref="tcp" port="8085">
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full" />
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>

6) Alter the program.cs for the Service project

using System;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Threading;

using Library;

namespace Service
{
class Program
{
private static ConcreteSubject _concreteSubject;

static void Main(string[] args)
{
try
{
RemotingConfiguration.Configure("Service.exe.config", false);
Console.WriteLine("Service is configured");

_concreteSubject = new ConcreteSubject();
RemotingServices.Marshal(_concreteSubject, "ConcreteSubject.rem", typeof(ConcreteSubject));

KeepNotifying();

// Wait for user
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.ReadLine();
}
}

private static void KeepNotifying()
{
while (true)
{
Thread.Sleep(2000);

_concreteSubject.SubjectState = "ABC";

Console.WriteLine("Notifying clients...");
_concreteSubject.Notify();
}
}
}
}

7) Create an app.config in the Client project

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown type="Library.ConcreteSubject, Library" url="tcp://localhost:8085/ConcreteSubject.rem" />
</client>
<channels>
<channel ref="tcp" port="0">
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>

8) Alter the program.cs for the Client project

using System;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Threading;
using Library;

namespace Client
{
class Program
{
private static ConcreteObserver _observer;

static void Main(string[] args)
{
try
{
RemotingConfiguration.Configure("Client.exe.config", false);
Console.WriteLine("Client is configured");

Thread.Sleep(500);

ConcreteSubject s = new ConcreteSubject();

_observer = new ConcreteObserver(s);

s.Attach(_observer);

Console.ReadKey();

// By not detaching, an invalid state should occur.
// s.Detach(_observer);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.ReadLine();
}
}
}
}

9) Richt click solution - properties - set multiple startup projects - Set Client and Service to start

10) Run the program

Notice that the line s.Detach(_observer); has been put in comments
This means that the client does not properly clean up its registration.
So, if both programs are running, you see that the client is writing output, and the service tells when it is writing to clients.
Now shut down the client, but keep the server running
Notice that the console window says (at the next iteration) 'Client was removed' but at the same time, it keeps notifying other clients.

Now, uncomment the line s.Detach(_observer); and try the same procedureagain.
This time the client has unregistered itself and the server does not need to clean up.
You can see this because when you close the client (by pressingRETURN twice) there isNO line that says 'Client was removed'.

So, as a conclusion:
Whether or not the client cleans up after itself, it is always removed from the service if it is disconnected.

P.S. It appears you have to catch a SocketException instead of a RemotingException, so I was mistaken about that.

Hopefully this helps,
Kind regards,
Stefan

  • Marked As Answer byBruno Vellego Monday, September 21, 2009 12:56 PM
  •  
Stefan H.F. A.

Thank you very much Stefan and Dynamic !!!
I solve the problem using this:

public void Notify()
{
for (int i = _observers.Count - 1; i >= 0; i--)
{
try
{
_observers[i].SendMessage(_publisherMessage);
}
catch (Exception err)
{
_observers.RemoveAt(i);
}
}
}

and is working like i want

Realy thanks for the help guys

Bruno Vellego

Ok, great!

But be careful with catching the baseException class.

If a normal (business) exception occurs, the observer will also be removed, not only when the connection fails.

Stefan H.F. A.

You can use google to search for other answers

Custom Search

More Threads

• IPC: accessing client's Form from Server application
• Maximum requests handling by .NET Remoting
• How to Access NameObjectCollection Property of MBR Object using RemotingServices.Marhal ??? Any Thoughts?
• "Cannot connet to remote server"
• .Net Remoting over App Domains in the same process
• Two references on the same instance
• deserialze problem
• Communication hangs on Vista Laptop
• remoting in C++
• Customised Regional Settings and SQL Server and MSDE