470,632 Members | 1,891 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 470,632 developers. It's quick & easy.

How to use a non static delegate in .NET Remoting ???

I’m trying to build a generic Publisher-Subscriber that will work over the
net, so I’m using the Remoting.

I wish that the subscriber user will be notify about the messages sent by
the remote publisher, so I used delegate that the user will be able to set on
it his own function for that purpuse.

The trouble is that this delegate must not be static because there may be
many subscribers, and each subscriber may have different function hooking on
that delegate.

But if I don’t set this delegate to static I get an exception:
“An unhandled exception of type 'System.Security.SecurityException' occurred
in mscorlib.dll
Additional information: Type System.DelegateSerializationHolder and the
types derived from it (such as System.DelegateSerializationHolder) are not
permitted to be deserialized at this security level.”

How can I fix it???

--
Thanks
Sharon
Nov 16 '05 #1
15 5520
Hi Sharon,

Since .NET v1.1 Microsoft demand more security restrictions on remoting
serialization. As a result in .NET v1.0 it is was possible to create a
channel as
ChannelServices.RegisterChannel(new TcpChannel(XXX));
However, with v1.1 we need to do more work to relax those restrictions and
make handling events possible.

On the server site you relax those restrictions as follows

BinaryClientFormatterSinkProvider clientProvider = null;
BinaryServerFormatterSinkProvider serverProvider =
new BinaryServerFormatterSinkProvider();

serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;

IDictionary props = new Hashtable();
props["port"] = 4000;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(props,clientProvider,serverProvider);

ChannelServices.RegisterChannel(chan);

On the client site

BinaryClientFormatterSinkProvider clientProvider = new
BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider serverProvider = new
BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;

IDictionary props = new Hashtable();
props["port"] = 0;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(
props,clientProvider,serverProvider);

ChannelServices.RegisterChannel(chan);
--

HTH
Stoitcho Goutsev (100) [C# MVP]
"Sharon" <Sh****@discussions.microsoft.com> wrote in message
news:71**********************************@microsof t.com...
I'm trying to build a generic Publisher-Subscriber that will work over the
net, so I'm using the Remoting.

I wish that the subscriber user will be notify about the messages sent by
the remote publisher, so I used delegate that the user will be able to set
on
it his own function for that purpuse.

The trouble is that this delegate must not be static because there may be
many subscribers, and each subscriber may have different function hooking
on
that delegate.

But if I don't set this delegate to static I get an exception:
"An unhandled exception of type 'System.Security.SecurityException'
occurred
in mscorlib.dll
Additional information: Type System.DelegateSerializationHolder and the
types derived from it (such as System.DelegateSerializationHolder) are not
permitted to be deserialized at this security level."

How can I fix it???

--
Thanks
Sharon

Nov 16 '05 #2
Halleluiah! The Security Exception is gone and I can use non static delegates
in the remoting object.

BUT now, the object that holds this remote object locally (let’s call it
Holder) that also has a non static delegate used by the application Form,
Become null whenever a message arrived from the channel.
For sure these delegates are set correctly after the local reference is
obtained by calling new.
Note that the changes you asked me to do, forced me to set the Holder class
as Serializable ( [Serializable()] )

It did work when the delegate were static, but not correctly as you already
now, I mean that they did not turned to null.

Note also the Holder class is also the Sponsor of the remote object for
renewing the leas of the remote object so it will not die and up again when I
want him to stay alive with my settings.

What can I do so the Holder delegates will remain valid all the way?

---------------------------------------------------------------------------------
"Stoitcho Goutsev (100) [C# MVP]" wrote:
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Hi Sharon,

Since .NET v1.1 Microsoft demand more security restrictions on remoting
serialization. As a result in .NET v1.0 it is was possible to create a
channel as
ChannelServices.RegisterChannel(new TcpChannel(XXX));
However, with v1.1 we need to do more work to relax those restrictions and
make handling events possible.

On the server site you relax those restrictions as follows

BinaryClientFormatterSinkProvider clientProvider = null;
BinaryServerFormatterSinkProvider serverProvider =
new BinaryServerFormatterSinkProvider();

serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;

IDictionary props = new Hashtable();
props["port"] = 4000;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(props,clientProvider,serverProvider);

ChannelServices.RegisterChannel(chan);

On the client site

BinaryClientFormatterSinkProvider clientProvider = new
BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider serverProvider = new
BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;

IDictionary props = new Hashtable();
props["port"] = 0;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(
props,clientProvider,serverProvider);

ChannelServices.RegisterChannel(chan);

---

HTH
Stoitcho Goutsev (100) [C# MVP]

-----------------------------------------------------------------------------
"Sharon" <Sh****@discussions.microsoft.com> wrote in message
news:71**********************************@microsof t.com...
I'm trying to build a generic Publisher-Subscriber that will work over the
net, so I'm using the Remoting.

I wish that the subscriber user will be notify about the messages sent by
the remote publisher, so I used delegate that the user will be able to set
on it his own function for that purpuse.

The trouble is that this delegate must not be static because there may be
many subscribers, and each subscriber may have different function hooking on
that delegate.

But if I don't set this delegate to static I get an exception:
"An unhandled exception of type 'System.Security.SecurityException' occurred
in mscorlib.dll
Additional information: Type System.DelegateSerializationHolder and the
types derived from it (such as System.DelegateSerializationHolder) are not
permitted to be deserialized at this security level."

How can I fix it???

--
Thanks
Sharon

Nov 16 '05 #3
Sharon,
Actually I couldn't get the problem. Is it possible to write simple example
that deonstrates the problem.

--

Stoitcho Goutsev (100) [C# MVP]
"Sharon" <Sh****@discussions.microsoft.com> wrote in message
news:DE**********************************@microsof t.com...
Halleluiah! The Security Exception is gone and I can use non static
delegates
in the remoting object.

BUT now, the object that holds this remote object locally (let's call it
Holder) that also has a non static delegate used by the application Form,
Become null whenever a message arrived from the channel.
For sure these delegates are set correctly after the local reference is
obtained by calling new.
Note that the changes you asked me to do, forced me to set the Holder
class
as Serializable ( [Serializable()] )

It did work when the delegate were static, but not correctly as you
already
now, I mean that they did not turned to null.

Note also the Holder class is also the Sponsor of the remote object for
renewing the leas of the remote object so it will not die and up again
when I
want him to stay alive with my settings.

What can I do so the Holder delegates will remain valid all the way?

---------------------------------------------------------------------------------
"Stoitcho Goutsev (100) [C# MVP]" wrote:
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Hi Sharon,

Since .NET v1.1 Microsoft demand more security restrictions on remoting
serialization. As a result in .NET v1.0 it is was possible to create a
channel as
ChannelServices.RegisterChannel(new TcpChannel(XXX));
However, with v1.1 we need to do more work to relax those restrictions and
make handling events possible.

On the server site you relax those restrictions as follows

BinaryClientFormatterSinkProvider clientProvider = null;
BinaryServerFormatterSinkProvider serverProvider =
new BinaryServerFormatterSinkProvider();

serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;

IDictionary props = new Hashtable();
props["port"] = 4000;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(props,clientProvider,serverProvider);

ChannelServices.RegisterChannel(chan);

On the client site

BinaryClientFormatterSinkProvider clientProvider = new
BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider serverProvider = new
BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;

IDictionary props = new Hashtable();
props["port"] = 0;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(
props,clientProvider,serverProvider);

ChannelServices.RegisterChannel(chan);

---

HTH
Stoitcho Goutsev (100) [C# MVP]

-----------------------------------------------------------------------------
"Sharon" <Sh****@discussions.microsoft.com> wrote in message
news:71**********************************@microsof t.com...
I'm trying to build a generic Publisher-Subscriber that will work over the
net, so I'm using the Remoting.

I wish that the subscriber user will be notify about the messages sent by
the remote publisher, so I used delegate that the user will be able to set
on it his own function for that purpuse.

The trouble is that this delegate must not be static because there may be
many subscribers, and each subscriber may have different function hooking
on
that delegate.

But if I don't set this delegate to static I get an exception:
"An unhandled exception of type 'System.Security.SecurityException'
occurred
in mscorlib.dll
Additional information: Type System.DelegateSerializationHolder and the
types derived from it (such as System.DelegateSerializationHolder) are not
permitted to be deserialized at this security level."

How can I fix it???

--
Thanks
Sharon

Nov 16 '05 #4
Well, here is the code example with some remark describing the bug.
Note: The classes: Subscriber, SubscriberMarshal are in a DLL and the
SubscriberUserForm in a EXE using this DLL.

public delegate void NotificationDelegate(object notification);
public delegate void AppNotificationDelegate(object notification, int port);
public class SubscriberMarshal : MarshalByRefObject
{
public NotificationDelegate notificationDelegate = null;

public SubscriberMarshal() {}
~SubscriberMarshal() {}

// The notification message does arrive to this point from the publisher
public void Notify(object notification)
{
// The notificationDelegate is set and the notification
// is forwarded to the Subscriber
if( notificationDelegate != null ) {
notificationDelegate.BeginInvoke(notification, null, 0);
}
}
}

[Serializable()]
public class Subscriber : ISponsor, IDisposable
{
public AppNotificationDelegate appNotificationDelegate = null;
private SubscriberMarshal m_SubscriberMarshal = null;

public Subscriber(string subscriberHost,
int subscriberPort,
string subscriberUri,
string publisherHost,
int publisherPort)
{
BinaryClientFormatterSinkProvider clientProvider = new
BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider serverProvider = new
BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;

IDictionary props = new Hashtable();
props["name"] = "tcp" + subscriberPort.ToString();
props["port"] = subscriberPort;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(props, clientProvider, serverProvider);
ChannelServices.RegisterChannel(chan);

RemotingConfiguration.RegisterWellKnownServiceType ( typeof(RemoteSubscriber.SubscriberMarshal),
subscriberUri,
WellKnownObjectMode.Singleton);

m_SubscriberMarshal =
(SubscriberMarshal)Activator.GetObject(typeof(Remo teSubscriber.SubscriberMarshal),
"tcp://" + subscriberHost + ":" + subscriberPort.ToString() + "/" +
subscriberUri);

m_SubscriberInfo = new SubscriberInfo(subscriberHost, subscriberUri,
subscriberPort);

m_SubscriberMarshal.notificationDelegate += new
NotificationDelegate(NotifyHandlerFwr);

ILease leas = (ILease)m_SubscriberMarshal.GetLifetimeService();
leas.Register(this);
}

// The notification message does arrive to this point from the publisher
public void NotifyHandlerFwr(object notification)
{
// The appNotificationDelegate became null, there for the application
// form is not informed about the notification. ==> THE BUG
if( appNotificationDelegate != null ) {
appNotificationDelegate.BeginInvoke(notification, m_SubscriberInfo.Port,
null, 0);
}
}

// ISponsor Implementation
public TimeSpan Renewal(ILease lease)
{
ILease leas = (ILease) m_SubscriberMarshal.GetLifetimeService();

if( m_Disposed )
{ leas.Unregister(this); }
return leas.InitialLeaseTime;
}

// IDisposable Implementation
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
if( !m_Disposed ) {
if( disposing ) {
ILease leas = (ILease)m_SubscriberMarshal.GetLifetimeService();
leas.Unregister(this);

IChannel [] channels = ChannelServices.RegisteredChannels;
foreach( IChannel channel in channels )
{ ChannelServices.UnregisterChannel(channel); }
}
}
m_Disposed = true;
}
}

public class SubscriberUserForm : System.Windows.Forms.Form
{
private int m_SubscriberPortEnum;
private ArrayList m_Subscribers = new ArrayList();

. . .

private void SubscribeButton_Click(object sender, System.EventArgs e)
{
m_SubscriberPortEnum = Convert.ToInt32(SuscriberPortTextBox.Text);
int PublishererPortNum = Convert.ToInt32(PublisherPortTextBox.Text);
Subscriber subscriber = new Subscriber (Environment.MachineName,
m_SubscriberPortEnum,
"RemoteSubscriberURI",
PublisherHostTextBox.Text,
PublishererPortNum);

subscriber.appNotificationDelegate += new
AppNotificationDelegate(NotificationHandler);
m_Subscribers.Add(subscriber);
}

// This method is never called !!!!!! ==> THE BUG
public void NotificationHandler(object notification, int port)
{
MessageBox.Show(notification.ToString(),
"subscriber Form Notification Handler - Port " + port.ToString(),
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
}

---------------------------------------------------------------------------------
"Stoitcho Goutsev (100) [C# MVP]" wrote:

Sharon,
Actually I couldn't get the problem. Is it possible to write simple example
that demonstrates the problem?

----
Stoitcho Goutsev (100) [C# MVP]

---------------------------------------------------------------------------------
"Sharon" <Sh****@discussions.microsoft.com wrote in message
news:DE**********************************@microsof t.com...
Halleluiah! The Security Exception is gone and I can use non static
delegates in the remoting object.

BUT now, the object that holds this remote object locally (let's call it
Holder) that also has a non static delegate used by the application Form,
Become null whenever a message arrived from the channel.
For sure these delegates are set correctly after the local reference is
obtained by calling new.
Note that the changes you asked me to do, forced me to set the Holder
Class as Serializable ( [Serializable()] )

It did work when the delegate were static, but not correctly as you already
now, I mean that they did not turned to null.

Note also the Holder class is also the Sponsor of the remote object for
renewing the leas of the remote object so it will not die and up again when I
want him to stay alive with my settings.

What can I do so the Holder delegates will remain valid all the way?

---------------------------------------------------------------------------------
"Stoitcho Goutsev (100) [C# MVP]" wrote:
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Hi Sharon,

Since .NET v1.1 Microsoft demand more security restrictions on remoting
serialization. As a result in .NET v1.0 it is was possible to create a
channel as
ChannelServices.RegisterChannel(new TcpChannel(XXX));
However, with v1.1 we need to do more work to relax those restrictions and
make handling events possible.

On the server site you relax those restrictions as follows

BinaryClientFormatterSinkProvider clientProvider = null;
BinaryServerFormatterSinkProvider serverProvider =
new BinaryServerFormatterSinkProvider();

serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;

IDictionary props = new Hashtable();
props["port"] = 4000;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(props,clientProvider,serverProvider);

ChannelServices.RegisterChannel(chan);

On the client site

BinaryClientFormatterSinkProvider clientProvider = new
BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider serverProvider = new
BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
IDictionary props = new Hashtable();
props["port"] = 0;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(
props,clientProvider,serverProvider);
ChannelServices.RegisterChannel(chan);

---
HTH
Stoitcho Goutsev (100) [C# MVP]

-----------------------------------------------------------------------------
"Sharon" <Sh****@discussions.microsoft.com wrote in message
news:71**********************************@microsof t.com...
I'm trying to build a generic Publisher-Subscriber that will work over the
net, so I'm using the Remoting.

I wish that the subscriber user will be notify about the messages sent by
the remote publisher, so I used delegate that the user will be able to set on
it his own function for that purpose.

The trouble is that this delegate must not be static because there may be
many subscribers, and each subscriber may have different function hooking on
that delegate.
But if I don't set this delegate to static I get an exception:
"An unhandled exception of type 'System.Security.SecurityException' occurred
in mscorlib.dll
Additional information: Type System.DelegateSerializationHolder and the
types derived from it (such as System.DelegateSerializationHolder) are not
permitted to be deserialized at this security level."

How can I fix it???

--
Thanks
Sharon
Nov 16 '05 #5
Hi Sharon,

The only reason for that, as far as I can see without to be able to compile
and debug your sample, would be that the Subscriber is actually marshaled by
value (It doesn't inherit form MarshalByRef).

In this case when you subscribe for
m_SubscriberMarshal.notificationDelegate what actually happens is your
object is serialized and deserialized on the server side (the server gets
totally new copy of the object) At this point you haven't subscribed for
subscriber.appNotificationDelegate event yet. So the server may fire its
event, but the copy of the subscriber object on the server has no event
handlers attached. So what you may try to do is:
1. Make the subscriber marshal by reference object
-- or --
2. Attach subscriber.appNotificationDelegate event handler before hooking on
m_SubscriberMarshal.notificationDelegate. It might work as long as the
object that handles subscriber.appNotificationDelegate event is decalred as
marshal by ref.

--
HTH
Stoitcho Goutsev (100) [C# MVP]
"Sharon" <Sh****@discussions.microsoft.com> wrote in message
news:2D**********************************@microsof t.com...
Well, here is the code example with some remark describing the bug.
Note: The classes: Subscriber, SubscriberMarshal are in a DLL and the
SubscriberUserForm in a EXE using this DLL.

public delegate void NotificationDelegate(object notification);
public delegate void AppNotificationDelegate(object notification, int
port);
public class SubscriberMarshal : MarshalByRefObject
{
public NotificationDelegate notificationDelegate = null;

public SubscriberMarshal() {}
~SubscriberMarshal() {}

// The notification message does arrive to this point from the publisher
public void Notify(object notification)
{
// The notificationDelegate is set and the notification
// is forwarded to the Subscriber
if( notificationDelegate != null ) {
notificationDelegate.BeginInvoke(notification, null, 0);
}
}
}

[Serializable()]
public class Subscriber : ISponsor, IDisposable
{
public AppNotificationDelegate appNotificationDelegate = null;
private SubscriberMarshal m_SubscriberMarshal = null;

public Subscriber(string subscriberHost,
int subscriberPort,
string subscriberUri,
string publisherHost,
int publisherPort)
{
BinaryClientFormatterSinkProvider clientProvider = new
BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider serverProvider = new
BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;

IDictionary props = new Hashtable();
props["name"] = "tcp" + subscriberPort.ToString();
props["port"] = subscriberPort;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(props, clientProvider, serverProvider);
ChannelServices.RegisterChannel(chan);

RemotingConfiguration.RegisterWellKnownServiceType (
typeof(RemoteSubscriber.SubscriberMarshal),
subscriberUri,
WellKnownObjectMode.Singleton);

m_SubscriberMarshal =
(SubscriberMarshal)Activator.GetObject(typeof(Remo teSubscriber.SubscriberMarshal),
"tcp://" + subscriberHost + ":" + subscriberPort.ToString() + "/" +
subscriberUri);

m_SubscriberInfo = new SubscriberInfo(subscriberHost, subscriberUri,
subscriberPort);

m_SubscriberMarshal.notificationDelegate += new
NotificationDelegate(NotifyHandlerFwr);

ILease leas = (ILease)m_SubscriberMarshal.GetLifetimeService();
leas.Register(this);
}

// The notification message does arrive to this point from the publisher
public void NotifyHandlerFwr(object notification)
{
// The appNotificationDelegate became null, there for the application
// form is not informed about the notification. ==> THE BUG
if( appNotificationDelegate != null ) {
appNotificationDelegate.BeginInvoke(notification, m_SubscriberInfo.Port,
null, 0);
}
}

// ISponsor Implementation
public TimeSpan Renewal(ILease lease)
{
ILease leas = (ILease) m_SubscriberMarshal.GetLifetimeService();

if( m_Disposed )
{ leas.Unregister(this); }
return leas.InitialLeaseTime;
}

// IDisposable Implementation
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
if( !m_Disposed ) {
if( disposing ) {
ILease leas = (ILease)m_SubscriberMarshal.GetLifetimeService();
leas.Unregister(this);

IChannel [] channels = ChannelServices.RegisteredChannels;
foreach( IChannel channel in channels )
{ ChannelServices.UnregisterChannel(channel); }
}
}
m_Disposed = true;
}
}

public class SubscriberUserForm : System.Windows.Forms.Form
{
private int m_SubscriberPortEnum;
private ArrayList m_Subscribers = new ArrayList();

. . .

private void SubscribeButton_Click(object sender, System.EventArgs e)
{
m_SubscriberPortEnum = Convert.ToInt32(SuscriberPortTextBox.Text);
int PublishererPortNum = Convert.ToInt32(PublisherPortTextBox.Text);
Subscriber subscriber = new Subscriber (Environment.MachineName,
m_SubscriberPortEnum,
"RemoteSubscriberURI",
PublisherHostTextBox.Text,
PublishererPortNum);

subscriber.appNotificationDelegate += new
AppNotificationDelegate(NotificationHandler);
m_Subscribers.Add(subscriber);
}

// This method is never called !!!!!! ==> THE BUG
public void NotificationHandler(object notification, int port)
{
MessageBox.Show(notification.ToString(),
"subscriber Form Notification Handler - Port " + port.ToString(),
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
}

---------------------------------------------------------------------------------
"Stoitcho Goutsev (100) [C# MVP]" wrote:

Sharon,
Actually I couldn't get the problem. Is it possible to write simple
example
that demonstrates the problem?

----
Stoitcho Goutsev (100) [C# MVP]

---------------------------------------------------------------------------------
"Sharon" <Sh****@discussions.microsoft.com wrote in message
news:DE**********************************@microsof t.com...
Halleluiah! The Security Exception is gone and I can use non static
delegates in the remoting object.

BUT now, the object that holds this remote object locally (let's call it
Holder) that also has a non static delegate used by the application Form,
Become null whenever a message arrived from the channel.
For sure these delegates are set correctly after the local reference is
obtained by calling new.
Note that the changes you asked me to do, forced me to set the Holder
Class as Serializable ( [Serializable()] )

It did work when the delegate were static, but not correctly as you
already
now, I mean that they did not turned to null.

Note also the Holder class is also the Sponsor of the remote object for
renewing the leas of the remote object so it will not die and up again
when I
want him to stay alive with my settings.

What can I do so the Holder delegates will remain valid all the way?

---------------------------------------------------------------------------------
"Stoitcho Goutsev (100) [C# MVP]" wrote:
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Hi Sharon,

Since .NET v1.1 Microsoft demand more security restrictions on remoting
serialization. As a result in .NET v1.0 it is was possible to create a
channel as
ChannelServices.RegisterChannel(new TcpChannel(XXX));
However, with v1.1 we need to do more work to relax those restrictions and
make handling events possible.

On the server site you relax those restrictions as follows

BinaryClientFormatterSinkProvider clientProvider = null;
BinaryServerFormatterSinkProvider serverProvider =
new BinaryServerFormatterSinkProvider();

serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;

IDictionary props = new Hashtable();
props["port"] = 4000;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(props,clientProvider,serverProvider);

ChannelServices.RegisterChannel(chan);

On the client site

BinaryClientFormatterSinkProvider clientProvider = new
BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider serverProvider = new
BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
IDictionary props = new Hashtable();
props["port"] = 0;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(
props,clientProvider,serverProvider);
ChannelServices.RegisterChannel(chan);

---
HTH
Stoitcho Goutsev (100) [C# MVP]

-----------------------------------------------------------------------------
"Sharon" <Sh****@discussions.microsoft.com wrote in message
news:71**********************************@microsof t.com...
I'm trying to build a generic Publisher-Subscriber that will work over the
net, so I'm using the Remoting.

I wish that the subscriber user will be notify about the messages sent by
the remote publisher, so I used delegate that the user will be able to set
on
it his own function for that purpose.

The trouble is that this delegate must not be static because there may be
many subscribers, and each subscriber may have different function hooking
on
that delegate.
But if I don't set this delegate to static I get an exception:
"An unhandled exception of type 'System.Security.SecurityException'
occurred
in mscorlib.dll
Additional information: Type System.DelegateSerializationHolder and the
types derived from it (such as System.DelegateSerializationHolder) are not
permitted to be deserialized at this security level."

How can I fix it???

--
Thanks
Sharon

Nov 16 '05 #6
Hi Stoitcho,

You are absolutely right; I also find it to be the problem.
Yet there are two kind of solution, the one you mentioned, which I tried as
follow:

I set all the Subscriber members during the regular constructor call new, so
when the ISerializable.GetObjectData() is called, all members was initialized
correctly, making the mentioned problem to go away.

*** There is a much simpler solution:
--------------------------------------------
I used Activator.GetObject(...) in order to get a local reference for the
remoting object, this is not necessary, it’s causing for a proxy object
creation which I do not need. Instead I have changed the call to
RemotingServices.Marshal(...) for the remoting object that I created locally
using a regular new operator.
When I did that, the Subscriber class that uses the remoting object locally,
does not need to be marked as Serialized any more, and the above
ISerializable is not used at all and the bug has disappeared.

BUT now I have some different questions:
--( 1 )--
The Form application wish to delete the Subscriber object, so it the
following:
(a) Unregister from the publisher.
(b) Calls Subscriber Dispose, and this Dispose is doing:
RemotingServices.Unmarshal(m_SubscriberObjRef);
RemotingServices.Disconnect(m_SubscriberMarshal);
ChannelServices.UnregisterChannel(m_Channel);
m_SubscriberObjRef = null;// returned by
RemotingServices.Marshal(m_SubscriberMarshal)
m_SubscriberMarshal = null;
m_Channel = null;// The registered channel of the m_SubscriberMarshal
(c) Remove any reference of the Subscriber.
(d) Call GC.Collect();

But still the Subscriber does not die.
Note: I’m doing the same at the Publisher, and it does die.

Why the Subscriber does not die ???

--( 2 )–
In case both Subscriber and Publisher are at the same computer, Is there a
way that the Subscriber will obtain a reference to the Publisher in a way
that does not require Proxy? I mean instead of calling Activator.GetObject()
???

--( 3 )–
As you can see, the subscriber is only a client of the Publisher. For that I
also made the Subscriber Marshaled (derived from MarshalByRefObject). Is
there any way that only the Publisher will be Marshaled ???

I tried it by that the Subscriber is not derived from the
MarshalByRefObject, and the Subscriber will only set a callback function
through a Publisher delegate. But then I get an Exception that the TcpCahnnel
is not Serializable.
As there a way for that???

----
Many thanks
Sharon G.
---------------
"Stoitcho Goutsev (100) [C# MVP]" wrote:

Hi Sharon,

The only reason for that, as far as I can see without to be able to compile
and debug your sample, would be that the Subscriber is actually marshaled by
value (It doesn't inherit form MarshalByRef).

In this case when you subscribe for m_SubscriberMarshal.notificationDelegate
what actually happens is your object is serialized and deserialized on the
server side (the server gets totally new copy of the object) At this point
you haven't subscribed for
subscriber.appNotificationDelegate event yet. So the server may fire its
event, but the copy of the subscriber object on the server has no event
handlers attached. So what you may try to do is:
1. Make the subscriber marshal by reference object
-- or --
2. Attach subscriber.appNotificationDelegate event handler before hooking on
m_SubscriberMarshal.notificationDelegate. It might work as long as the
object that handles subscriber.appNotificationDelegate event is declared as
marshal by ref.

---------------
HTH
Stoitcho Goutsev (100) [C# MVP]
"Sharon" <Sh****@discussions.microsoft.comwrote in message
news:2D**********************************@microsof t.com...
Well, here is the code example with some remark describing the bug.
Note: The classes: Subscriber, SubscriberMarshal are in a DLL and the
SubscriberUserForm in a EXE using this DLL.

public delegate void NotificationDelegate(object notification);
public delegate void AppNotificationDelegate(object notification, int
port);
public class SubscriberMarshal : MarshalByRefObject
{
public NotificationDelegate notificationDelegate = null;

public SubscriberMarshal() {}
~SubscriberMarshal() {}

// The notification message does arrive to this point from the publisher
public void Notify(object notification)
{
// The notificationDelegate is set and the notification
// is forwarded to the Subscriber
if( notificationDelegate != null ) {
notificationDelegate.BeginInvoke(notification, null, 0);
}
}
}

[Serializable()]
public class Subscriber : ISponsor, IDisposable
{
public AppNotificationDelegate appNotificationDelegate = null;
private SubscriberMarshal m_SubscriberMarshal = null;

public Subscriber(string subscriberHost,
int subscriberPort,
string subscriberUri,
string publisherHost,
int publisherPort)
{
BinaryClientFormatterSinkProvider clientProvider = new
BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider serverProvider = new
BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;

IDictionary props = new Hashtable();
props["name"] = "tcp" + subscriberPort.ToString();
props["port"] = subscriberPort;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(props, clientProvider, serverProvider);
ChannelServices.RegisterChannel(chan);

RemotingConfiguration.RegisterWellKnownServiceType (
typeof(RemoteSubscriber.SubscriberMarshal),
subscriberUri,
WellKnownObjectMode.Singleton);

m_SubscriberMarshal =
(SubscriberMarshal)Activator.GetObject(typeof(Remo teSubscriber.SubscriberMarshal),
"tcp://" + subscriberHost + ":" + subscriberPort.ToString() + "/" +
subscriberUri);

m_SubscriberInfo = new SubscriberInfo(subscriberHost, subscriberUri,
subscriberPort);

m_SubscriberMarshal.notificationDelegate += new
NotificationDelegate(NotifyHandlerFwr);

ILease leas = (ILease)m_SubscriberMarshal.GetLifetimeService();
leas.Register(this);
}

// The notification message does arrive to this point from the publisher
public void NotifyHandlerFwr(object notification)
{
// The appNotificationDelegate became null, there for the application
// form is not informed about the notification. ==THE BUG
if( appNotificationDelegate != null ) {
appNotificationDelegate.BeginInvoke(notification, m_SubscriberInfo.Port,
null, 0);
}
}

// ISponsor Implementation
public TimeSpan Renewal(ILease lease)
{
ILease leas = (ILease) m_SubscriberMarshal.GetLifetimeService();

if( m_Disposed )
{ leas.Unregister(this); }
return leas.InitialLeaseTime;
}

// IDisposable Implementation
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
if( !m_Disposed ) {
if( disposing ) {
ILease leas = (ILease)m_SubscriberMarshal.GetLifetimeService();
leas.Unregister(this);

IChannel [] channels = ChannelServices.RegisteredChannels;
foreach( IChannel channel in channels )
{ ChannelServices.UnregisterChannel(channel); }
}
}
m_Disposed = true;
}
}

public class SubscriberUserForm : System.Windows.Forms.Form
{
private int m_SubscriberPortEnum;
private ArrayList m_Subscribers = new ArrayList();

.. . .

private void SubscribeButton_Click(object sender, System.EventArgs e)
{
m_SubscriberPortEnum = Convert.ToInt32(SuscriberPortTextBox.Text);
int PublishererPortNum = Convert.ToInt32(PublisherPortTextBox.Text);
Subscriber subscriber = new Subscriber (Environment.MachineName,
m_SubscriberPortEnum,
"RemoteSubscriberURI",
PublisherHostTextBox.Text,
PublishererPortNum);

subscriber.appNotificationDelegate += new
AppNotificationDelegate(NotificationHandler);
m_Subscribers.Add(subscriber);
}

// This method is never called !!!!!! ==THE BUG
public void NotificationHandler(object notification, int port)
{
MessageBox.Show(notification.ToString(),
"subscriber Form Notification Handler - Port " + port.ToString(),
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
}

---------------------------------------------------------------------------------
"Stoitcho Goutsev (100) [C# MVP]" wrote:

Sharon,
Actually I couldn't get the problem. Is it possible to write simple
example
that demonstrates the problem?

---------------
Stoitcho Goutsev (100) [C# MVP]

---------------------------------------------------------------------------------
"Sharon" <Sh****@discussions.microsoft.com wrote in message
news:DE**********************************@microsof t.com...
Halleluiah! The Security Exception is gone and I can use non static
delegates in the remoting object.

BUT now, the object that holds this remote object locally (let's call it
Holder) that also has a non static delegate used by the application Form,
Become null whenever a message arrived from the channel.
For sure these delegates are set correctly after the local reference is
obtained by calling new.
Note that the changes you asked me to do, forced me to set the Holder
Class as Serializable ( [Serializable()] )

It did work when the delegate were static, but not correctly as you already
now, I mean that they did not turned to null.

Note also the Holder class is also the Sponsor of the remote object for
renewing the leas of the remote object so it will not die and up again when I
want him to stay alive with my settings.

What can I do so the Holder delegates will remain valid all the way?

---------------------------------------------------------------------------------
"Stoitcho Goutsev (100) [C# MVP]" wrote:
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Hi Sharon,

Since .NET v1.1 Microsoft demand more security restrictions on remoting
serialization. As a result in .NET v1.0 it is was possible to create a
channel as ChannelServices.RegisterChannel(new TcpChannel(XXX));
However, with v1.1 we need to do more work to relax those restrictions and
make handling events possible.

On the server site you relax those restrictions as follows

BinaryClientFormatterSinkProvider clientProvider = null;
BinaryServerFormatterSinkProvider serverProvider = new
BinaryServerFormatterSinkProvider();

serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;

IDictionary props = new Hashtable();
props["port"] = 4000;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(props,clientProvider,serverProvider);

ChannelServices.RegisterChannel(chan);
On the client site:

BinaryClientFormatterSinkProvider clientProvider = new
BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider serverProvider = new
BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
IDictionary props = new Hashtable();
props["port"] = 0;
props["typeFilterLevel"] = TypeFilterLevel.Full;
TcpChannel chan = new TcpChannel(
props,clientProvider,serverProvider);
ChannelServices.RegisterChannel(chan);

---
HTH
Stoitcho Goutsev (100) [C# MVP]

-----------------------------------------------------------------------------
"Sharon" <Sh****@discussions.microsoft.com wrote in message
news:71**********************************@microsof t.com...
I'm trying to build a generic Publisher-Subscriber that will work over the
net, so I'm using the Remoting.

I wish that the subscriber user will be notify about the messages sent by
the remote publisher, so I used delegate that the user will be able to set on
it his own function for that purpose.

The trouble is that this delegate must not be static because there may be
many subscribers, and each subscriber may have different function hooking on
that delegate.
But if I don't set this delegate to static I get an exception:
"An unhandled exception of type 'System.Security.SecurityException' occurred
in mscorlib.dll
Additional information: Type System.DelegateSerializationHolder and the
types derived from it (such as System.DelegateSerializationHolder) are not
permitted to be deserialized at this security level."

How can I fix it???

--
Thanks
Sharon
Nov 16 '05 #7
Hi Sharon,

See me inlined
I used Activator.GetObject(...) in order to get a local reference for the
remoting object, this is not necessary, it's causing for a proxy object
creation which I do not need. Instead I have changed the call to
RemotingServices.Marshal(...) for the remoting object that I created
locally
using a regular new operator.
When I did that, the Subscriber class that uses the remoting object
locally,
does not need to be marked as Serialized any more, and the above
ISerializable is not used at all and the bug has disappeared
It works because your Ssubscriber now inherits from MarshalByRef. I don't
think you need that Marshal for the Subscriber. .NET remoting framework will
take care of this when you hook the remote object event.

--( 1 )--
The Form application wish to delete the Subscriber object, so it the
following:
(a) Unregister from the publisher.
(b) Calls Subscriber Dispose, and this Dispose is doing:
RemotingServices.Unmarshal(m_SubscriberObjRef);
RemotingServices.Disconnect(m_SubscriberMarshal);
ChannelServices.UnregisterChannel(m_Channel);
m_SubscriberObjRef = null;// returned by
RemotingServices.Marshal(m_SubscriberMarshal)
m_SubscriberMarshal = null;
m_Channel = null;// The registered channel of the m_SubscriberMarshal
(c) Remove any reference of the Subscriber.
(d) Call GC.Collect();

But still the Subscriber does not die.
Note: I'm doing the same at the Publisher, and it does die.

Why the Subscriber does not die ???
Fisrtly, how do you know that the subscriber doesn't die?
Does it have finalizer (destructor)? If it has it takes 2 GC collection
until the object dies.
Secondly, are you sure that you cut all the references to the object? I
don't see for example that you undregister the subscriber as a lease
sponsor. It is in the source code that you posted before, though.
Make sure that you don't hook more than once Publisher's event. As many
times you hook it the same number of times you need to unhook it in order to
clear all references
Bear in mind that every event the sunscriber might hook with some of its
instance members is a reference to it.

So I suspect that you still keep some reference to it

--( 2 )-
In case both Subscriber and Publisher are at the same computer, Is there a
way that the Subscriber will obtain a reference to the Publisher in a way
that does not require Proxy? I mean instead of calling
Activator.GetObject()
???

--( 3 )-
As you can see, the subscriber is only a client of the Publisher. For that
I
also made the Subscriber Marshaled (derived from MarshalByRefObject). Is
there any way that only the Publisher will be Marshaled ???
No, once you cross AppDomain boundries you need proxies and channels. Even
if both, subscribe and publisher, are in the same process, but in different
AppDomains you are going to need a proxy


I tried it by that the Subscriber is not derived from the
MarshalByRefObject, and the Subscriber will only set a callback function
through a Publisher delegate. But then I get an Exception that the
TcpCahnnel
is not Serializable.
As there a way for that???


When you subscribe for an event and the event handler is not a static member
of the class you need to pass a reference to the subscriber object. The
delegate keeps reference to the object + the handler method. As long as the
publisher and the subscriber live in different AppDomains in order to
subscribe for an event you need to marshal that reference to the handler's
object. It can be done in two ways:
1. The subscriber inhertits form MarshalByRef and proxies are created
2. The subscriber is marked as serializable in which case the subscriber is
serialized and deserialized on the server side thus, the event is hooked by
a new object one the server side.

--
HTH
Stoitcho Goutsev (100) [C# MVP]

Nov 16 '05 #8
Are you suggesting that I’ll roll back using the Activator.GetObject(...) to
get a local reference to the SubscriberMarshal (the remoting object) object
???

--( 1 )--
(*) Yes, the subscriber does have a destructor but it never called expect at
the application closing.
(*) Yes, I am sure that I cut all the references to the object; I checked it
over and over.
(*) Yes, at the Subscriber.Dispose() I’m unregistering the subscriber as a
lease sponsor of the SubscriberMarshal.
(*) No, it is not the same code any more, now it is changed as described as
the “much simpler solution”. I’ll be happy to post the new code in here if
you want me to.
(*) There is no more than one hook to Publisher's event, I know that because
I did code review and also because only one notification is arriving from the
Publisher.
(*) After what you said I tried to clear all delegates by setting them to
null: the delegates that the Subscriber uses (of the delegates
SubscriberMarshal) and the Subscriber’s delegates used by the Form.

But still Subscriber and the SubscriberMarshal does not die.
Note: I’m doing the same thing at the Publisher, and it does die as expected.
Why? Why? Why? ( expression of my despair...)
--( 2 & 3 )—
After viewing your suggestions, I think I’ll keep working as it is now.

--------------------------------------------------
"Stoitcho Goutsev (100) [C# MVP]" wrote:
Hi Sharon,

See me inlined
I used Activator.GetObject(...) in order to get a local reference for the
remoting object, this is not necessary, it's causing for a proxy object
creation which I do not need. Instead I have changed the call to
RemotingServices.Marshal(...) for the remoting object that I created
locally
using a regular new operator.
When I did that, the Subscriber class that uses the remoting object
locally,
does not need to be marked as Serialized any more, and the above
ISerializable is not used at all and the bug has disappeared


It works because your Ssubscriber now inherits from MarshalByRef. I don't
think you need that Marshal for the Subscriber. .NET remoting framework will
take care of this when you hook the remote object event.

--( 1 )--
The Form application wish to delete the Subscriber object, so it the
following:
(a) Unregister from the publisher.
(b) Calls Subscriber Dispose, and this Dispose is doing:
RemotingServices.Unmarshal(m_SubscriberObjRef);
RemotingServices.Disconnect(m_SubscriberMarshal);
ChannelServices.UnregisterChannel(m_Channel);
m_SubscriberObjRef = null;// returned by
RemotingServices.Marshal(m_SubscriberMarshal)
m_SubscriberMarshal = null;
m_Channel = null;// The registered channel of the m_SubscriberMarshal
(c) Remove any reference of the Subscriber.
(d) Call GC.Collect();

But still the Subscriber does not die.
Note: I'm doing the same at the Publisher, and it does die.

Why the Subscriber does not die ???


Fisrtly, how do you know that the subscriber doesn't die?
Does it have finalizer (destructor)? If it has it takes 2 GC collection
until the object dies.
Secondly, are you sure that you cut all the references to the object? I
don't see for example that you undregister the subscriber as a lease
sponsor. It is in the source code that you posted before, though.
Make sure that you don't hook more than once Publisher's event. As many
times you hook it the same number of times you need to unhook it in order to
clear all references
Bear in mind that every event the sunscriber might hook with some of its
instance members is a reference to it.

So I suspect that you still keep some reference to it

--( 2 )-
In case both Subscriber and Publisher are at the same computer, Is there a
way that the Subscriber will obtain a reference to the Publisher in a way
that does not require Proxy? I mean instead of calling
Activator.GetObject()
???

--( 3 )-
As you can see, the subscriber is only a client of the Publisher. For that
I
also made the Subscriber Marshaled (derived from MarshalByRefObject). Is
there any way that only the Publisher will be Marshaled ???


No, once you cross AppDomain boundries you need proxies and channels. Even
if both, subscribe and publisher, are in the same process, but in different
AppDomains you are going to need a proxy


I tried it by that the Subscriber is not derived from the
MarshalByRefObject, and the Subscriber will only set a callback function
through a Publisher delegate. But then I get an Exception that the
TcpCahnnel
is not Serializable.
As there a way for that???


When you subscribe for an event and the event handler is not a static member
of the class you need to pass a reference to the subscriber object. The
delegate keeps reference to the object + the handler method. As long as the
publisher and the subscriber live in different AppDomains in order to
subscribe for an event you need to marshal that reference to the handler's
object. It can be done in two ways:
1. The subscriber inhertits form MarshalByRef and proxies are created
2. The subscriber is marked as serializable in which case the subscriber is
serialized and deserialized on the server side thus, the event is hooked by
a new object one the server side.

--
HTH
Stoitcho Goutsev (100) [C# MVP]

Nov 16 '05 #9
Hi Sharon,

See me inlined
I used Activator.GetObject(...) in order to get a local reference for the
remoting object, this is not necessary, it's causing for a proxy object
creation which I do not need. Instead I have changed the call to
RemotingServices.Marshal(...) for the remoting object that I created
locally
using a regular new operator.
When I did that, the Subscriber class that uses the remoting object
locally,
does not need to be marked as Serialized any more, and the above
ISerializable is not used at all and the bug has disappeared
It works because your Ssubscriber now inherits from MarshalByRef. I don't
think you need that Marshal for the Subscriber. .NET remoting framework will
take care of this when you hook the remote object event.

--( 1 )--
The Form application wish to delete the Subscriber object, so it the
following:
(a) Unregister from the publisher.
(b) Calls Subscriber Dispose, and this Dispose is doing:
RemotingServices.Unmarshal(m_SubscriberObjRef);
RemotingServices.Disconnect(m_SubscriberMarshal);
ChannelServices.UnregisterChannel(m_Channel);
m_SubscriberObjRef = null;// returned by
RemotingServices.Marshal(m_SubscriberMarshal)
m_SubscriberMarshal = null;
m_Channel = null;// The registered channel of the m_SubscriberMarshal
(c) Remove any reference of the Subscriber.
(d) Call GC.Collect();

But still the Subscriber does not die.
Note: I'm doing the same at the Publisher, and it does die.

Why the Subscriber does not die ???
Fisrtly, how do you know that the subscriber doesn't die?
Does it have finalizer (destructor)? If it has it takes 2 GC collection
until the object dies.
Secondly, are you sure that you cut all the references to the object? I
don't see for example that you undregister the subscriber as a lease
sponsor. It is in the source code that you posted before, though.
Make sure that you don't hook more than once Publisher's event. As many
times you hook it the same number of times you need to unhook it in order to
clear all references
Bear in mind that every event the sunscriber might hook with some of its
instance members is a reference to it.

So I suspect that you still keep some reference to it

--( 2 )-
In case both Subscriber and Publisher are at the same computer, Is there a
way that the Subscriber will obtain a reference to the Publisher in a way
that does not require Proxy? I mean instead of calling
Activator.GetObject()
???

--( 3 )-
As you can see, the subscriber is only a client of the Publisher. For that
I
also made the Subscriber Marshaled (derived from MarshalByRefObject). Is
there any way that only the Publisher will be Marshaled ???
No, once you cross AppDomain boundries you need proxies and channels. Even
if both, subscribe and publisher, are in the same process, but in different
AppDomains you are going to need a proxy


I tried it by that the Subscriber is not derived from the
MarshalByRefObject, and the Subscriber will only set a callback function
through a Publisher delegate. But then I get an Exception that the
TcpCahnnel
is not Serializable.
As there a way for that???


When you subscribe for an event and the event handler is not a static member
of the class you need to pass a reference to the subscriber object. The
delegate keeps reference to the object + the handler method. As long as the
publisher and the subscriber live in different AppDomains in order to
subscribe for an event you need to marshal that reference to the handler's
object. It can be done in two ways:
1. The subscriber inhertits form MarshalByRef and proxies are created
2. The subscriber is marked as serializable in which case the subscriber is
serialized and deserialized on the server side thus, the event is hooked by
a new object one the server side.

--
HTH
Stoitcho Goutsev (100) [C# MVP]

Nov 16 '05 #10
Are you suggesting that I’ll roll back using the Activator.GetObject(...) to
get a local reference to the SubscriberMarshal (the remoting object) object
???

--( 1 )—NEWS:
Ooops, I found the standing referencing. It was the delegate setting of the
SubscriberMarshal that remain pointing on the Subscriber handlers.

But still, The Marshaled object (SubscriberMarshal & PublisherMarshal) are
not dieing, I guess they will die after their lease will expire after a few
more minutes ??

--( 2 & 3 )—
After viewing your suggestions, I think I’ll keep working as it is now.

--------------------
Thanks & Regards
Sharon
Nov 16 '05 #11
Are you suggesting that I’ll roll back using the Activator.GetObject(...) to
get a local reference to the SubscriberMarshal (the remoting object) object
???

--( 1 )--
(*) Yes, the subscriber does have a destructor but it never called expect at
the application closing.
(*) Yes, I am sure that I cut all the references to the object; I checked it
over and over.
(*) Yes, at the Subscriber.Dispose() I’m unregistering the subscriber as a
lease sponsor of the SubscriberMarshal.
(*) No, it is not the same code any more, now it is changed as described as
the “much simpler solution”. I’ll be happy to post the new code in here if
you want me to.
(*) There is no more than one hook to Publisher's event, I know that because
I did code review and also because only one notification is arriving from the
Publisher.
(*) After what you said I tried to clear all delegates by setting them to
null: the delegates that the Subscriber uses (of the delegates
SubscriberMarshal) and the Subscriber’s delegates used by the Form.

But still Subscriber and the SubscriberMarshal does not die.
Note: I’m doing the same thing at the Publisher, and it does die as expected.
Why? Why? Why? ( expression of my despair...)
--( 2 & 3 )—
After viewing your suggestions, I think I’ll keep working as it is now.

--------------------------------------------------
"Stoitcho Goutsev (100) [C# MVP]" wrote:
Hi Sharon,

See me inlined
I used Activator.GetObject(...) in order to get a local reference for the
remoting object, this is not necessary, it's causing for a proxy object
creation which I do not need. Instead I have changed the call to
RemotingServices.Marshal(...) for the remoting object that I created
locally
using a regular new operator.
When I did that, the Subscriber class that uses the remoting object
locally,
does not need to be marked as Serialized any more, and the above
ISerializable is not used at all and the bug has disappeared


It works because your Ssubscriber now inherits from MarshalByRef. I don't
think you need that Marshal for the Subscriber. .NET remoting framework will
take care of this when you hook the remote object event.

--( 1 )--
The Form application wish to delete the Subscriber object, so it the
following:
(a) Unregister from the publisher.
(b) Calls Subscriber Dispose, and this Dispose is doing:
RemotingServices.Unmarshal(m_SubscriberObjRef);
RemotingServices.Disconnect(m_SubscriberMarshal);
ChannelServices.UnregisterChannel(m_Channel);
m_SubscriberObjRef = null;// returned by
RemotingServices.Marshal(m_SubscriberMarshal)
m_SubscriberMarshal = null;
m_Channel = null;// The registered channel of the m_SubscriberMarshal
(c) Remove any reference of the Subscriber.
(d) Call GC.Collect();

But still the Subscriber does not die.
Note: I'm doing the same at the Publisher, and it does die.

Why the Subscriber does not die ???


Fisrtly, how do you know that the subscriber doesn't die?
Does it have finalizer (destructor)? If it has it takes 2 GC collection
until the object dies.
Secondly, are you sure that you cut all the references to the object? I
don't see for example that you undregister the subscriber as a lease
sponsor. It is in the source code that you posted before, though.
Make sure that you don't hook more than once Publisher's event. As many
times you hook it the same number of times you need to unhook it in order to
clear all references
Bear in mind that every event the sunscriber might hook with some of its
instance members is a reference to it.

So I suspect that you still keep some reference to it

--( 2 )-
In case both Subscriber and Publisher are at the same computer, Is there a
way that the Subscriber will obtain a reference to the Publisher in a way
that does not require Proxy? I mean instead of calling
Activator.GetObject()
???

--( 3 )-
As you can see, the subscriber is only a client of the Publisher. For that
I
also made the Subscriber Marshaled (derived from MarshalByRefObject). Is
there any way that only the Publisher will be Marshaled ???


No, once you cross AppDomain boundries you need proxies and channels. Even
if both, subscribe and publisher, are in the same process, but in different
AppDomains you are going to need a proxy


I tried it by that the Subscriber is not derived from the
MarshalByRefObject, and the Subscriber will only set a callback function
through a Publisher delegate. But then I get an Exception that the
TcpCahnnel
is not Serializable.
As there a way for that???


When you subscribe for an event and the event handler is not a static member
of the class you need to pass a reference to the subscriber object. The
delegate keeps reference to the object + the handler method. As long as the
publisher and the subscriber live in different AppDomains in order to
subscribe for an event you need to marshal that reference to the handler's
object. It can be done in two ways:
1. The subscriber inhertits form MarshalByRef and proxies are created
2. The subscriber is marked as serializable in which case the subscriber is
serialized and deserialized on the server side thus, the event is hooked by
a new object one the server side.

--
HTH
Stoitcho Goutsev (100) [C# MVP]

Nov 16 '05 #12
Are you suggesting that I’ll roll back using the Activator.GetObject(...) to
get a local reference to the SubscriberMarshal (the remoting object) object
???

--( 1 )—NEWS:
Ooops, I found the standing referencing. It was the delegate setting of the
SubscriberMarshal that remain pointing on the Subscriber handlers.

But still, The Marshaled object (SubscriberMarshal & PublisherMarshal) are
not dieing, I guess they will die after their lease will expire after a few
more minutes ??

--( 2 & 3 )—
After viewing your suggestions, I think I’ll keep working as it is now.

--------------------
Thanks & Regards
Sharon
Nov 16 '05 #13
Hi Sharon,

Yes, you can post your code. It would be even more helpful if you could
create a compilable sample that I can run on my machine and debug.
Are you suggesting that I'll roll back using the Activator.GetObject(...)
to
get a local reference to the SubscriberMarshal (the remoting object)
object
Frankly, I don't suggest anything. I just want to say that your
SubscriberMarshal doesn't have to be registered (or marshaled) if it is not
instantiated from remote code. In you case I believe that the remote part
doesn't use Activator.GetObject to get reference to the subscriber. If you
create the subscriber marshal in the cleint side via *new* opretator the
frame work will take care of marshaling the object (creating a proxy for it)
as soon as you subscribe for the server's event. This is in case where
Subscriber inherits from MarshalByRef. But again I couldn't be certain
unless I don't have code that I can compile and run.
Looking on your code again I feel like I'm lost. I feel like I imagine
different architecture.
So here how I imagine your architecture

Server end:
-----------
declares Publisher class and registers publisher as Singleton well-know type
RegisterWellKnowServiceType(publisher,....)
Client end:
----------
Declares Subscruber and SubscriberMarshal. SubscriberMarshal is a class that
will be marshaled back to the server and its main role is to retranslate the
event. This is done because you don't want to serialize or marshal the
actual Subscriber object. SubscriberMarhsal inherits form
MarshalByRefObject. Its type is also shared by the server and the client.

On the other hand Subscriber (the actual client) doesn't have to be neither
marshal by ref nor serializable. Its type is know only by the client.

Getting reference to the publisher (well, getting a reference to a proxy not
the real object). As such we need to maintain its lifetime

publisher = Activator.GetObject(publisher,.....)
SubscriberMarshal subscriberMarshal = new SubscribeMarhal()
subscriberMarshal.LocalNotification += new NotificationDelegate
(subscriber.NotificationHandler)

The next line will marshal back our event retranslator (SubscriberMarshal)
to the server side, but the subcirber itself won't be marhsaled, so it
doesn't have to be marked as Serializable or MarshalByRefObject
publisher.Notification += new
NotificationHandler(sunscriberMarshal.RemoteNotifi cationHandler)
Now when the publisher raise its Notification event it will be handled in
the SubscriberMarshal and retranslated (reraised) on the client side

--
HTH
Stoitcho Goutsev (100) [C# MVP]
"Sharon" <Sh****@discussions.microsoft.com> wrote in message
news:BA**********************************@microsof t.com... Are you suggesting that I'll roll back using the Activator.GetObject(...)
to
get a local reference to the SubscriberMarshal (the remoting object)
object
???

--( 1 )-NEWS:
Ooops, I found the standing referencing. It was the delegate setting of
the
SubscriberMarshal that remain pointing on the Subscriber handlers.

But still, The Marshaled object (SubscriberMarshal & PublisherMarshal) are
not dieing, I guess they will die after their lease will expire after a
few
more minutes ??

--( 2 & 3 )-
After viewing your suggestions, I think I'll keep working as it is now.

--------------------
Thanks & Regards
Sharon

Nov 16 '05 #14
Hi Stoitcho,

I thing you understand me right.

But to make sure here is the code trimmed with any unnecessary lines.
I hope will be able to compile it and figure me out all the way.

### The Code ####

namespace RemoteSubscriber
{
// Delegates for Publisher
public delegate void NewSubscriberNotificationDelegate(int count);
public delegate void SubscriberRemovalNotificationDelegate(int count);

// Delegates for Subscriber
public delegate void SubscriberRemovedDelegate(Subscriber subscriber);
public delegate void AppNotificationDelegate(object notification, int port);

// Delegates for SubscriberMrashal
public delegate void NotificationDelegate(object notification);
public delegate void UnSbscribedDelegate();

/// <summary>
/// Publisher client and hold and manage the SubscriberMrashal
/// (which are local)
/// </summary>
public class Subscriber : ISponsor, IDisposable
{
[Serializable()]
public class SubscriberInfo
{
public string HostName;
public string URI;
public int Port;

public SubscriberInfo(string hostName, string uri, int port) {
this.HostName = hostName;
this.URI = uri;
this.Port = port;
}

public static bool operator ==(SubscriberInfo thisInfo, SubscriberInfo
otherInfo)
{
if( thisInfo.HostName == otherInfo.HostName &&
thisInfo.URI == otherInfo.URI &&
thisInfo.Port == otherInfo.Port )
{ return true; }
else
{ return false; }
}

public static bool operator !=(SubscriberInfo thisInfo, SubscriberInfo
otherInfo)
{
return !(thisInfo == otherInfo);
}
}

public AppNotificationDelegate appNotificationDelegate = null;
public NotificationDelegate notificationDelegate = null;
public SubscriberRemovedDelegate unsbscribedDelegate = null;

private SubscriberMarshal m_SubscriberMarshal = null;
private PublisherMarshal m_Publisher = null;
private SubscriberInfo m_SubscriberInfo = null;
private ObjRef m_SubscriberObjRef = null;
private TcpChannel m_Channel = null;
private bool m_Disposed = false;
private bool m_UnSubscribedByPublisher = false;
public Subscriber(string publisherHost,
int publisherPort,
int subscriberPort)
{
IDictionary properties = new Hashtable();
properties["name"] = "tcp" + subscriberPort.ToString();
properties["port"] = subscriberPort;
m_Channel = new TcpChannel(properties, null, new
BinaryServerFormatterSinkProvider());
ChannelServices.RegisterChannel(m_Channel);

m_SubscriberMarshal = new SubscriberMarshal();
m_SubscriberObjRef = RemotingServices.Marshal(m_SubscriberMarshal,
"RemoteSubscriberURI_#" + subscriberPort.ToString(),
typeof(SubscriberMarshal));

m_SubscriberInfo = new SubscriberInfo(Environment.MachineName,
"RemoteSubscriberURI_#" + subscriberPort.ToString(), subscriberPort);
ActivatePublisher(publisherHost, publisherPort);

m_SubscriberMarshal.notificationDelegate += new
NotificationDelegate(NotifyHandlerFwr);
m_SubscriberMarshal.unsbscribedDelegate += new
UnSbscribedDelegate(UnSubscribed);

ILease leas = (ILease)m_SubscriberMarshal.GetLifetimeService();
leas.Register(this);
}

~Subscriber() {}

private void ActivatePublisher(string publisherHost, int publisherPort)
{
m_Publisher =
(PublisherMarshal)Activator.GetObject(typeof(Remot ePublisher.PublisherMarshal),
"tcp://" + publisherHost + ":" + publisherPort + "/RemotingPublisherURI");
}

public void Subscribe() {
m_Publisher.Subscribe(m_SubscriberInfo);
}

public void UnSubscribe() {
if( ! m_UnSubscribedByPublisher )
{
m_Publisher.UnSubscribe(m_SubscriberInfo);
}
if( m_SubscriberObjRef != null )
{
RemotingServices.Unmarshal(m_SubscriberObjRef);
m_SubscriberObjRef = null;
}
if( m_SubscriberMarshal != null )
{
ILease leas = (ILease)m_SubscriberMarshal.GetLifetimeService();
leas.Unregister(this);

// Cleaning any pointing from the m_SubscriberMarshal
// so it will marked for deletion by the GC.
RemotingServices.Disconnect(m_SubscriberMarshal);
m_SubscriberMarshal.notificationDelegate = null;
m_SubscriberMarshal.unsbscribedDelegate = null;
m_SubscriberMarshal = null;
}
if( m_Channel != null ) {
ChannelServices.UnregisterChannel(m_Channel);
m_Channel = null;
}
}

/// <summary>
/// Called by the publisher when the publisher initiate the
/// subscriber removal.
/// </summary>
public void UnSubscribed() {
m_UnSubscribedByPublisher = true;

if( unsbscribedDelegate != null ) {
unsbscribedDelegate.BeginInvoke(this, null, 0);
}
}

public void NotifyHandlerFwr(object notification)
{
if( notificationDelegate != null ) {
notificationDelegate.BeginInvoke(notification, null, 0);
}

if( appNotificationDelegate != null ) {
appNotificationDelegate.BeginInvoke(notification, m_SubscriberInfo.Port,
null, 0);
}
}

#region ISponsor Members

public TimeSpan Renewal(ILease lease)
{
if( m_Disposed ){
lease.Unregister(this);
}
return lease.InitialLeaseTime;
}

#endregion

#region IDisposable Members

public void Dispose()
{
Dispose(true);
}

private void Dispose(bool disposing)
{
if( !m_Disposed ) {
if( disposing ) {
if( m_SubscriberMarshal != null )
{
ILease leas = (ILease)m_SubscriberMarshal.GetLifetimeService();
leas.Unregister(this);
}
m_Publisher.UnSubscribe(m_SubscriberInfo);

if( m_SubscriberObjRef != null ) {
RemotingServices.Unmarshal(m_SubscriberObjRef);
m_SubscriberObjRef = null;
}
if( m_SubscriberMarshal != null ) {
RemotingServices.Disconnect(m_SubscriberMarshal);
m_SubscriberMarshal.notificationDelegate = null;
m_SubscriberMarshal.unsbscribedDelegate = null;
m_SubscriberMarshal = null;
}
if( m_Channel != null ) {
ChannelServices.UnregisterChannel(m_Channel);
m_Channel = null;
}
}
}
m_Disposed = true;
}

#endregion
}

/// <summary>
/// The remoting subscriber
/// </summary>
public class SubscriberMarshal : MarshalByRefObject
{
public NotificationDelegate notificationDelegate = null;
public UnSbscribedDelegate unsbscribedDelegate = null;
public SubscriberMarshal() {}

~SubscriberMarshal() {}
public void Notify(object notification) {
if( notificationDelegate != null )
notificationDelegate.BeginInvoke(notification, null, 0);
}

/// <summary>
/// Called by the publisher when the publisher initiate the
/// subscriber removal.
/// </summary>
public void UnSbscribed() {
if( unsbscribedDelegate != null )
unsbscribedDelegate.BeginInvoke(null, 0);
}
}

// The remoting Publisher
public class PublisherMarshal : MarshalByRefObject
{
/// Store the remote subscriber reference together with its network data.
private class SubscriberStorage
{
public SubscriberMarshal subscriber;
public Subscriber.SubscriberInfo subscriberInfo;

public SubscriberStorage(SubscriberMarshal subscriber,
Subscriber.SubscriberInfo subscriberInfo)
{
this.subscriber = subscriber;
this.subscriberInfo = subscriberInfo;
}
}

public NewSubscriberNotificationDelegate newSubscriberDelegate = null;
public SubscriberRemovalNotificationDelegate remSubscriberDelegate = null;
private ArrayList m_Subscribers = new ArrayList();
private bool m_UnSubscribingAll = false;

public PublisherMarshal() {}
~PublisherMarshal() {}

public void Subscribe(Subscriber.SubscriberInfo subscriberInfo)
{
SubscriberMarshal remSubscriber =
(SubscriberMarshal)Activator.GetObject(typeof(Remo teSubscriber.SubscriberMarshal),
"tcp://" + subscriberInfo.HostName + ":" + subscriberInfo.Port + "/" +
subscriberInfo.URI);

SubscriberStorage storage = new SubscriberStorage(remSubscriber,
subscriberInfo);
m_Subscribers.Add(storage);

if( newSubscriberDelegate != null )
newSubscriberDelegate.BeginInvoke(this.Subscribers Count, null, 0);
}

public void UnSubscribe(Subscriber.SubscriberInfo subscriberInfo)
{
for( int i=0; i<m_Subscribers.Count; ++i ) {
SubscriberStorage storage = (SubscriberStorage)m_Subscribers[i];

if( storage.subscriberInfo == subscriberInfo ) {
if( ! m_UnSubscribingAll ) {
m_Subscribers.RemoveAt(i);
}

if( remSubscriberDelegate != null ) {
remSubscriberDelegate.BeginInvoke(this.Subscribers Count, null, 0);
}
break;
}
}
}

public void UnSubscribeAll()
{
m_UnSubscribingAll = true;

foreach( SubscriberStorage storage in m_Subscribers )
storage.subscriber.UnSbscribed();

m_Subscribers.Clear();

if( remSubscriberDelegate != null )
remSubscriberDelegate.BeginInvoke(0, null, 0);

m_UnSubscribingAll = false;
}

public void Notify(object notification)
{
for( int i=0; i<m_Subscribers.Count; ++i )
((SubscriberStorage)m_Subscribers[i]).subscriber.Notify(notification);
}
}
}

### End of Code ####
Nov 16 '05 #15
Hi Sharon,

I think this discution started discusing very specific things so, it is not
anymore of any interest to the general public. I'd suggest to wrap it up and
if you want to you can contact me at guzzev_at_yahoo_dot_com to continue
working on your issues. Looking on the last code you posted I believe there
is more to simplify. I've prepared a sample solution that shows my vision
over the problem. It is not that closely replated to your exact project, but
demonstrates the architecture from my perspective. Just send me an email and
I'll mail it to you.

--

Stoitcho Goutsev (100) [C# MVP]
"Sharon" <Sh****@discussions.microsoft.com> wrote in message
news:DD**********************************@microsof t.com...
Hi Stoitcho,

I thing you understand me right.

But to make sure here is the code trimmed with any unnecessary lines.
I hope will be able to compile it and figure me out all the way.

### The Code ####

namespace RemoteSubscriber
{
// Delegates for Publisher
public delegate void NewSubscriberNotificationDelegate(int count);
public delegate void SubscriberRemovalNotificationDelegate(int count);

// Delegates for Subscriber
public delegate void SubscriberRemovedDelegate(Subscriber subscriber);
public delegate void AppNotificationDelegate(object notification, int
port);

// Delegates for SubscriberMrashal
public delegate void NotificationDelegate(object notification);
public delegate void UnSbscribedDelegate();

/// <summary>
/// Publisher client and hold and manage the SubscriberMrashal
/// (which are local)
/// </summary>
public class Subscriber : ISponsor, IDisposable
{
[Serializable()]
public class SubscriberInfo
{
public string HostName;
public string URI;
public int Port;

public SubscriberInfo(string hostName, string uri, int port) {
this.HostName = hostName;
this.URI = uri;
this.Port = port;
}

public static bool operator ==(SubscriberInfo thisInfo, SubscriberInfo
otherInfo)
{
if( thisInfo.HostName == otherInfo.HostName &&
thisInfo.URI == otherInfo.URI &&
thisInfo.Port == otherInfo.Port )
{ return true; }
else
{ return false; }
}

public static bool operator !=(SubscriberInfo thisInfo, SubscriberInfo
otherInfo)
{
return !(thisInfo == otherInfo);
}
}

public AppNotificationDelegate appNotificationDelegate = null;
public NotificationDelegate notificationDelegate = null;
public SubscriberRemovedDelegate unsbscribedDelegate = null;

private SubscriberMarshal m_SubscriberMarshal = null;
private PublisherMarshal m_Publisher = null;
private SubscriberInfo m_SubscriberInfo = null;
private ObjRef m_SubscriberObjRef = null;
private TcpChannel m_Channel = null;
private bool m_Disposed = false;
private bool m_UnSubscribedByPublisher = false;
public Subscriber(string publisherHost,
int publisherPort,
int subscriberPort)
{
IDictionary properties = new Hashtable();
properties["name"] = "tcp" + subscriberPort.ToString();
properties["port"] = subscriberPort;
m_Channel = new TcpChannel(properties, null, new
BinaryServerFormatterSinkProvider());
ChannelServices.RegisterChannel(m_Channel);

m_SubscriberMarshal = new SubscriberMarshal();
m_SubscriberObjRef = RemotingServices.Marshal(m_SubscriberMarshal,
"RemoteSubscriberURI_#" + subscriberPort.ToString(),
typeof(SubscriberMarshal));

m_SubscriberInfo = new SubscriberInfo(Environment.MachineName,
"RemoteSubscriberURI_#" + subscriberPort.ToString(), subscriberPort);
ActivatePublisher(publisherHost, publisherPort);

m_SubscriberMarshal.notificationDelegate += new
NotificationDelegate(NotifyHandlerFwr);
m_SubscriberMarshal.unsbscribedDelegate += new
UnSbscribedDelegate(UnSubscribed);

ILease leas = (ILease)m_SubscriberMarshal.GetLifetimeService();
leas.Register(this);
}

~Subscriber() {}

private void ActivatePublisher(string publisherHost, int publisherPort)
{
m_Publisher =
(PublisherMarshal)Activator.GetObject(typeof(Remot ePublisher.PublisherMarshal),
"tcp://" + publisherHost + ":" + publisherPort + "/RemotingPublisherURI");
}

public void Subscribe() {
m_Publisher.Subscribe(m_SubscriberInfo);
}

public void UnSubscribe() {
if( ! m_UnSubscribedByPublisher )
{
m_Publisher.UnSubscribe(m_SubscriberInfo);
}
if( m_SubscriberObjRef != null )
{
RemotingServices.Unmarshal(m_SubscriberObjRef);
m_SubscriberObjRef = null;
}
if( m_SubscriberMarshal != null )
{
ILease leas = (ILease)m_SubscriberMarshal.GetLifetimeService();
leas.Unregister(this);

// Cleaning any pointing from the m_SubscriberMarshal
// so it will marked for deletion by the GC.
RemotingServices.Disconnect(m_SubscriberMarshal);
m_SubscriberMarshal.notificationDelegate = null;
m_SubscriberMarshal.unsbscribedDelegate = null;
m_SubscriberMarshal = null;
}
if( m_Channel != null ) {
ChannelServices.UnregisterChannel(m_Channel);
m_Channel = null;
}
}

/// <summary>
/// Called by the publisher when the publisher initiate the
/// subscriber removal.
/// </summary>
public void UnSubscribed() {
m_UnSubscribedByPublisher = true;

if( unsbscribedDelegate != null ) {
unsbscribedDelegate.BeginInvoke(this, null, 0);
}
}

public void NotifyHandlerFwr(object notification)
{
if( notificationDelegate != null ) {
notificationDelegate.BeginInvoke(notification, null, 0);
}

if( appNotificationDelegate != null ) {
appNotificationDelegate.BeginInvoke(notification, m_SubscriberInfo.Port,
null, 0);
}
}

#region ISponsor Members

public TimeSpan Renewal(ILease lease)
{
if( m_Disposed ){
lease.Unregister(this);
}
return lease.InitialLeaseTime;
}

#endregion

#region IDisposable Members

public void Dispose()
{
Dispose(true);
}

private void Dispose(bool disposing)
{
if( !m_Disposed ) {
if( disposing ) {
if( m_SubscriberMarshal != null )
{
ILease leas = (ILease)m_SubscriberMarshal.GetLifetimeService();
leas.Unregister(this);
}
m_Publisher.UnSubscribe(m_SubscriberInfo);

if( m_SubscriberObjRef != null ) {
RemotingServices.Unmarshal(m_SubscriberObjRef);
m_SubscriberObjRef = null;
}
if( m_SubscriberMarshal != null ) {
RemotingServices.Disconnect(m_SubscriberMarshal);
m_SubscriberMarshal.notificationDelegate = null;
m_SubscriberMarshal.unsbscribedDelegate = null;
m_SubscriberMarshal = null;
}
if( m_Channel != null ) {
ChannelServices.UnregisterChannel(m_Channel);
m_Channel = null;
}
}
}
m_Disposed = true;
}

#endregion
}

/// <summary>
/// The remoting subscriber
/// </summary>
public class SubscriberMarshal : MarshalByRefObject
{
public NotificationDelegate notificationDelegate = null;
public UnSbscribedDelegate unsbscribedDelegate = null;
public SubscriberMarshal() {}

~SubscriberMarshal() {}
public void Notify(object notification) {
if( notificationDelegate != null )
notificationDelegate.BeginInvoke(notification, null, 0);
}

/// <summary>
/// Called by the publisher when the publisher initiate the
/// subscriber removal.
/// </summary>
public void UnSbscribed() {
if( unsbscribedDelegate != null )
unsbscribedDelegate.BeginInvoke(null, 0);
}
}

// The remoting Publisher
public class PublisherMarshal : MarshalByRefObject
{
/// Store the remote subscriber reference together with its network data.
private class SubscriberStorage
{
public SubscriberMarshal subscriber;
public Subscriber.SubscriberInfo subscriberInfo;

public SubscriberStorage(SubscriberMarshal subscriber,
Subscriber.SubscriberInfo subscriberInfo)
{
this.subscriber = subscriber;
this.subscriberInfo = subscriberInfo;
}
}

public NewSubscriberNotificationDelegate newSubscriberDelegate = null;
public SubscriberRemovalNotificationDelegate remSubscriberDelegate = null;
private ArrayList m_Subscribers = new ArrayList();
private bool m_UnSubscribingAll = false;

public PublisherMarshal() {}
~PublisherMarshal() {}

public void Subscribe(Subscriber.SubscriberInfo subscriberInfo)
{
SubscriberMarshal remSubscriber =
(SubscriberMarshal)Activator.GetObject(typeof(Remo teSubscriber.SubscriberMarshal),
"tcp://" + subscriberInfo.HostName + ":" + subscriberInfo.Port + "/" +
subscriberInfo.URI);

SubscriberStorage storage = new SubscriberStorage(remSubscriber,
subscriberInfo);
m_Subscribers.Add(storage);

if( newSubscriberDelegate != null )
newSubscriberDelegate.BeginInvoke(this.Subscribers Count, null, 0);
}

public void UnSubscribe(Subscriber.SubscriberInfo subscriberInfo)
{
for( int i=0; i<m_Subscribers.Count; ++i ) {
SubscriberStorage storage = (SubscriberStorage)m_Subscribers[i];

if( storage.subscriberInfo == subscriberInfo ) {
if( ! m_UnSubscribingAll ) {
m_Subscribers.RemoveAt(i);
}

if( remSubscriberDelegate != null ) {
remSubscriberDelegate.BeginInvoke(this.Subscribers Count, null, 0);
}
break;
}
}
}

public void UnSubscribeAll()
{
m_UnSubscribingAll = true;

foreach( SubscriberStorage storage in m_Subscribers )
storage.subscriber.UnSbscribed();

m_Subscribers.Clear();

if( remSubscriberDelegate != null )
remSubscriberDelegate.BeginInvoke(0, null, 0);

m_UnSubscribingAll = false;
}

public void Notify(object notification)
{
for( int i=0; i<m_Subscribers.Count; ++i )
((SubscriberStorage)m_Subscribers[i]).subscriber.Notify(notification);
}
}
}

### End of Code ####

Nov 16 '05 #16

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

1 post views Thread by Nicky | last post: by
1 post views Thread by Nadav | last post: by
4 posts views Thread by Michael C | last post: by
2 posts views Thread by superseed | last post: by
reply views Thread by Joe Van Meer | last post: by
6 posts views Thread by =?Utf-8?B?TWF0dA==?= | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.