How Can a Server Raise an Event at a Client (Remoting)

  • Thread starter Thread starter Charles Law
  • Start date Start date
C

Charles Law

I've read numerous articles and bits of code that purport to do this, but I
think there is a gap somewhere (quite possibly in my head).

I have a server, which is actually a Windows service. I also have a client
that needs to retrieve information from this service, but also needs to
receive events from it, when it (the client) is running. I've done all the
MBO stuff, and the client can pick up info from the server at will. That was
the easy bit.

Now, I want the service/server to be able to raise an event, and the client
to handle it. The sticking point seems to be: How do I raise the event in
the server? It seems to me that in order to do that I need a reference to
the MBO on which the event is to be raised. In my server I have

Dim identifier As String = "MyServer"
Dim mode As WellKnownObjectMode = WellKnownObjectMode.Singleton
Dim entry As WellKnownServiceTypeEntry
entry = New WellKnownServiceTypeEntry(GetType(MyServerMBO), identifier,
mode)
RemotingConfiguration.RegisterWellKnownServiceType(entry)

But how do I get a reference to the MyServerMBO that is created?

I have tried making everything Shared, so that I don't need a reference, but
although I can see the RaiseEvent call being made, the debugger steps right
over it, indicating that there is nothing attached to it, and the client
never receives a call.

Have I missed something here?

TIA

Charles
 
You may want to look into CallBack in WCF (why still Remoting when WCF gives
you a better tool to use?).
 
Hi Norman

Thanks for the very quick response. The main reason for not going WCF (yet)
is the learning curve. That said, if it solves the problem where my current
approach is taking time to get right, perhaps I would be better spending a
few hours looking at WCF now. Just knowing that it can do it for me might be
the incentive I need.

Charles
 
Charles,

I would recommend against using an event in this situation. Rather,
have a shared interface which represents the callback from the server to the
client, and then implement an instance of that object on the client side,
making sure the class derives from MarshalByRefObject. Then, expose a
method on the service which takes an instance of this implementation and
pass your MarshalByRefObject to that method on the service.

This allows the service to call back into the client. Then, you can
have that object raise events which other classes can respond to. I don't
recommend calling back directly to say, the UI, because the calls will come
in on threads other than the UI thread.
 
Hi Nicholas

Thanks for the reply. I think I have half done what you suggest already. I
have a class in the server that inherits from MarshalByRefObject. I create
an instance of that in the client, and then use it to sink events raised by
the server. By passing this object to the server on which to raise its
events, it seems that the server and client would be quite tightly bound
together though. If the client goes away without telling the server
(crashes), the server would try to raise events on an object that doesn't
exist, but where the reference is not nothing. Then what would happen?

I'm not sure that solution gets over the UI thread issue either. The event
will always be on the wrong thread until it is marshalled to the right
thread, or BeginInvoke is used. I think I would have to do that in any case.

Charles


Nicholas Paldino said:
Charles,

I would recommend against using an event in this situation. Rather,
have a shared interface which represents the callback from the server to
the client, and then implement an instance of that object on the client
side, making sure the class derives from MarshalByRefObject. Then, expose
a method on the service which takes an instance of this implementation and
pass your MarshalByRefObject to that method on the service.

This allows the service to call back into the client. Then, you can
have that object raise events which other classes can respond to. I don't
recommend calling back directly to say, the UI, because the calls will
come in on threads other than the UI thread.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Charles Law said:
I've read numerous articles and bits of code that purport to do this, but
I think there is a gap somewhere (quite possibly in my head).

I have a server, which is actually a Windows service. I also have a
client that needs to retrieve information from this service, but also
needs to receive events from it, when it (the client) is running. I've
done all the MBO stuff, and the client can pick up info from the server
at will. That was the easy bit.

Now, I want the service/server to be able to raise an event, and the
client to handle it. The sticking point seems to be: How do I raise the
event in the server? It seems to me that in order to do that I need a
reference to the MBO on which the event is to be raised. In my server I
have

Dim identifier As String = "MyServer"
Dim mode As WellKnownObjectMode = WellKnownObjectMode.Singleton
Dim entry As WellKnownServiceTypeEntry
entry = New WellKnownServiceTypeEntry(GetType(MyServerMBO), identifier,
mode)
RemotingConfiguration.RegisterWellKnownServiceType(entry)

But how do I get a reference to the MyServerMBO that is created?

I have tried making everything Shared, so that I don't need a reference,
but although I can see the RaiseEvent call being made, the debugger steps
right over it, indicating that there is nothing attached to it, and the
client never receives a call.

Have I missed something here?

TIA

Charles
 
Charles,

There is no solution that is going to get over the message coming in on
a non-UI thread. It just complicates things when the implementation of the
callback interface on the client is on the UI object itself. You are better
off having a separate object on the client that derives from MBRO and then
exposes events that other objects can respond to. Any calls from the server
to the client which result in updating the UI will have to be marshaled from
the callback to the UI thread.

Regarding the server and the client being tightly bound, this is no more
the case than when you use events. Yes, the server has a reference to the
client, but with events, the same thing occurs.

If the client goes away (in this case, the object implementing the
callback interface, or the server, for that matter, since they both derive
from MBRO), then the lease will expire, and the proxy on the other end will
be invalidated.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)


Charles Law said:
Hi Nicholas

Thanks for the reply. I think I have half done what you suggest already. I
have a class in the server that inherits from MarshalByRefObject. I create
an instance of that in the client, and then use it to sink events raised
by the server. By passing this object to the server on which to raise its
events, it seems that the server and client would be quite tightly bound
together though. If the client goes away without telling the server
(crashes), the server would try to raise events on an object that doesn't
exist, but where the reference is not nothing. Then what would happen?

I'm not sure that solution gets over the UI thread issue either. The event
will always be on the wrong thread until it is marshalled to the right
thread, or BeginInvoke is used. I think I would have to do that in any
case.

Charles


Nicholas Paldino said:
Charles,

I would recommend against using an event in this situation. Rather,
have a shared interface which represents the callback from the server to
the client, and then implement an instance of that object on the client
side, making sure the class derives from MarshalByRefObject. Then,
expose a method on the service which takes an instance of this
implementation and pass your MarshalByRefObject to that method on the
service.

This allows the service to call back into the client. Then, you can
have that object raise events which other classes can respond to. I
don't recommend calling back directly to say, the UI, because the calls
will come in on threads other than the UI thread.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Charles Law said:
I've read numerous articles and bits of code that purport to do this,
but I think there is a gap somewhere (quite possibly in my head).

I have a server, which is actually a Windows service. I also have a
client that needs to retrieve information from this service, but also
needs to receive events from it, when it (the client) is running. I've
done all the MBO stuff, and the client can pick up info from the server
at will. That was the easy bit.

Now, I want the service/server to be able to raise an event, and the
client to handle it. The sticking point seems to be: How do I raise the
event in the server? It seems to me that in order to do that I need a
reference to the MBO on which the event is to be raised. In my server I
have

Dim identifier As String = "MyServer"
Dim mode As WellKnownObjectMode = WellKnownObjectMode.Singleton
Dim entry As WellKnownServiceTypeEntry
entry = New WellKnownServiceTypeEntry(GetType(MyServerMBO), identifier,
mode)
RemotingConfiguration.RegisterWellKnownServiceType(entry)

But how do I get a reference to the MyServerMBO that is created?

I have tried making everything Shared, so that I don't need a reference,
but although I can see the RaiseEvent call being made, the debugger
steps right over it, indicating that there is nothing attached to it,
and the client never receives a call.

Have I missed something here?

TIA

Charles
 
Is there a way to determine if the lease has expired, and does it expire
immediately? A test I just did suggests that it doesn't. I killed my client
and allowed the server to attempt to raise another event. I got an exception
to the effect that the "machine had actively refused the connection". Is
there a neater way than just trap the exception when it occurs? Obviously,
in normal operation the client would tell the server that it was going away,
but what if it doesn't?

In my case, there will be quite regular communication between server and
client (when one is running), but to be on the safe side I override
InitializeLifetimeService. Would that cause a problem?

I think I can see a way to make this work for me, using your suggestion, but
bits of it just seem a little inelegant. For example, if this were a
listener then it would need to attach to another process and listen without
the other process being aware, and detach without upsetting the main
process. It would also not impact the main process performance because it
would listen asynchronously. I think of it like a recital. It doesn't affect
the performer whether there are one, ten or none listening. The recital
continues the same. That's really all I am trying to do here.

Regards

Charles


Nicholas Paldino said:
Charles,

There is no solution that is going to get over the message coming in on
a non-UI thread. It just complicates things when the implementation of
the callback interface on the client is on the UI object itself. You are
better off having a separate object on the client that derives from MBRO
and then exposes events that other objects can respond to. Any calls from
the server to the client which result in updating the UI will have to be
marshaled from the callback to the UI thread.

Regarding the server and the client being tightly bound, this is no
more the case than when you use events. Yes, the server has a reference
to the client, but with events, the same thing occurs.

If the client goes away (in this case, the object implementing the
callback interface, or the server, for that matter, since they both derive
from MBRO), then the lease will expire, and the proxy on the other end
will be invalidated.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)


Charles Law said:
Hi Nicholas

Thanks for the reply. I think I have half done what you suggest already.
I have a class in the server that inherits from MarshalByRefObject. I
create an instance of that in the client, and then use it to sink events
raised by the server. By passing this object to the server on which to
raise its events, it seems that the server and client would be quite
tightly bound together though. If the client goes away without telling
the server (crashes), the server would try to raise events on an object
that doesn't exist, but where the reference is not nothing. Then what
would happen?

I'm not sure that solution gets over the UI thread issue either. The
event will always be on the wrong thread until it is marshalled to the
right thread, or BeginInvoke is used. I think I would have to do that in
any case.

Charles


Nicholas Paldino said:
Charles,

I would recommend against using an event in this situation. Rather,
have a shared interface which represents the callback from the server to
the client, and then implement an instance of that object on the client
side, making sure the class derives from MarshalByRefObject. Then,
expose a method on the service which takes an instance of this
implementation and pass your MarshalByRefObject to that method on the
service.

This allows the service to call back into the client. Then, you can
have that object raise events which other classes can respond to. I
don't recommend calling back directly to say, the UI, because the calls
will come in on threads other than the UI thread.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

I've read numerous articles and bits of code that purport to do this,
but I think there is a gap somewhere (quite possibly in my head).

I have a server, which is actually a Windows service. I also have a
client that needs to retrieve information from this service, but also
needs to receive events from it, when it (the client) is running. I've
done all the MBO stuff, and the client can pick up info from the server
at will. That was the easy bit.

Now, I want the service/server to be able to raise an event, and the
client to handle it. The sticking point seems to be: How do I raise the
event in the server? It seems to me that in order to do that I need a
reference to the MBO on which the event is to be raised. In my server I
have

Dim identifier As String = "MyServer"
Dim mode As WellKnownObjectMode = WellKnownObjectMode.Singleton
Dim entry As WellKnownServiceTypeEntry
entry = New WellKnownServiceTypeEntry(GetType(MyServerMBO), identifier,
mode)
RemotingConfiguration.RegisterWellKnownServiceType(entry)

But how do I get a reference to the MyServerMBO that is created?

I have tried making everything Shared, so that I don't need a
reference, but although I can see the RaiseEvent call being made, the
debugger steps right over it, indicating that there is nothing attached
to it, and the client never receives a call.

Have I missed something here?

TIA

Charles
 
Charles,

You can try and get the ILease implementation of the other side. You
just have to call the static GetLifetimeService method on the
RemotingServices class, passing the service proxy to it, and casting the
return value to ILease.

You should then be able to check the CurrentState property of the ILease
implementation to get the state of the lease.

I can't see why overriding InitializeLifetimeService would cause a
problem, but then again, I don't know what you are doing in it, so I can't
say for sure.

I can undersand what you are trying to do, but under the covers, using
events or callbacks over remoting, the fact of the matter is that the server
has to be aware of the client in some manner in order to fire the event or
perform the callback. The eventing just doesn't work as nicely as a
callback interface, as there are a lot of hoops to jump through.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Charles Law said:
Is there a way to determine if the lease has expired, and does it expire
immediately? A test I just did suggests that it doesn't. I killed my
client and allowed the server to attempt to raise another event. I got an
exception to the effect that the "machine had actively refused the
connection". Is there a neater way than just trap the exception when it
occurs? Obviously, in normal operation the client would tell the server
that it was going away, but what if it doesn't?

In my case, there will be quite regular communication between server and
client (when one is running), but to be on the safe side I override
InitializeLifetimeService. Would that cause a problem?

I think I can see a way to make this work for me, using your suggestion,
but bits of it just seem a little inelegant. For example, if this were a
listener then it would need to attach to another process and listen
without the other process being aware, and detach without upsetting the
main process. It would also not impact the main process performance
because it would listen asynchronously. I think of it like a recital. It
doesn't affect the performer whether there are one, ten or none listening.
The recital continues the same. That's really all I am trying to do here.

Regards

Charles


Nicholas Paldino said:
Charles,

There is no solution that is going to get over the message coming in
on a non-UI thread. It just complicates things when the implementation
of the callback interface on the client is on the UI object itself. You
are better off having a separate object on the client that derives from
MBRO and then exposes events that other objects can respond to. Any
calls from the server to the client which result in updating the UI will
have to be marshaled from the callback to the UI thread.

Regarding the server and the client being tightly bound, this is no
more the case than when you use events. Yes, the server has a reference
to the client, but with events, the same thing occurs.

If the client goes away (in this case, the object implementing the
callback interface, or the server, for that matter, since they both
derive from MBRO), then the lease will expire, and the proxy on the other
end will be invalidated.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)


Charles Law said:
Hi Nicholas

Thanks for the reply. I think I have half done what you suggest already.
I have a class in the server that inherits from MarshalByRefObject. I
create an instance of that in the client, and then use it to sink events
raised by the server. By passing this object to the server on which to
raise its events, it seems that the server and client would be quite
tightly bound together though. If the client goes away without telling
the server (crashes), the server would try to raise events on an object
that doesn't exist, but where the reference is not nothing. Then what
would happen?

I'm not sure that solution gets over the UI thread issue either. The
event will always be on the wrong thread until it is marshalled to the
right thread, or BeginInvoke is used. I think I would have to do that in
any case.

Charles


in message Charles,

I would recommend against using an event in this situation. Rather,
have a shared interface which represents the callback from the server
to the client, and then implement an instance of that object on the
client side, making sure the class derives from MarshalByRefObject.
Then, expose a method on the service which takes an instance of this
implementation and pass your MarshalByRefObject to that method on the
service.

This allows the service to call back into the client. Then, you can
have that object raise events which other classes can respond to. I
don't recommend calling back directly to say, the UI, because the calls
will come in on threads other than the UI thread.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

I've read numerous articles and bits of code that purport to do this,
but I think there is a gap somewhere (quite possibly in my head).

I have a server, which is actually a Windows service. I also have a
client that needs to retrieve information from this service, but also
needs to receive events from it, when it (the client) is running. I've
done all the MBO stuff, and the client can pick up info from the
server at will. That was the easy bit.

Now, I want the service/server to be able to raise an event, and the
client to handle it. The sticking point seems to be: How do I raise
the event in the server? It seems to me that in order to do that I
need a reference to the MBO on which the event is to be raised. In my
server I have

Dim identifier As String = "MyServer"
Dim mode As WellKnownObjectMode = WellKnownObjectMode.Singleton
Dim entry As WellKnownServiceTypeEntry
entry = New WellKnownServiceTypeEntry(GetType(MyServerMBO),
identifier, mode)
RemotingConfiguration.RegisterWellKnownServiceType(entry)

But how do I get a reference to the MyServerMBO that is created?

I have tried making everything Shared, so that I don't need a
reference, but although I can see the RaiseEvent call being made, the
debugger steps right over it, indicating that there is nothing
attached to it, and the client never receives a call.

Have I missed something here?

TIA

Charles
 
Hi Nicholas

I'll try the ILease thing, but it might just be that with the activity I
expect it will never expire.

Thanks for all your help. It's much appreciated.

Cheers

Charles


Nicholas Paldino said:
Charles,

You can try and get the ILease implementation of the other side. You
just have to call the static GetLifetimeService method on the
RemotingServices class, passing the service proxy to it, and casting the
return value to ILease.

You should then be able to check the CurrentState property of the
ILease implementation to get the state of the lease.

I can't see why overriding InitializeLifetimeService would cause a
problem, but then again, I don't know what you are doing in it, so I can't
say for sure.

I can undersand what you are trying to do, but under the covers, using
events or callbacks over remoting, the fact of the matter is that the
server has to be aware of the client in some manner in order to fire the
event or perform the callback. The eventing just doesn't work as nicely
as a callback interface, as there are a lot of hoops to jump through.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Charles Law said:
Is there a way to determine if the lease has expired, and does it expire
immediately? A test I just did suggests that it doesn't. I killed my
client and allowed the server to attempt to raise another event. I got an
exception to the effect that the "machine had actively refused the
connection". Is there a neater way than just trap the exception when it
occurs? Obviously, in normal operation the client would tell the server
that it was going away, but what if it doesn't?

In my case, there will be quite regular communication between server and
client (when one is running), but to be on the safe side I override
InitializeLifetimeService. Would that cause a problem?

I think I can see a way to make this work for me, using your suggestion,
but bits of it just seem a little inelegant. For example, if this were a
listener then it would need to attach to another process and listen
without the other process being aware, and detach without upsetting the
main process. It would also not impact the main process performance
because it would listen asynchronously. I think of it like a recital. It
doesn't affect the performer whether there are one, ten or none
listening. The recital continues the same. That's really all I am trying
to do here.

Regards

Charles


Nicholas Paldino said:
Charles,

There is no solution that is going to get over the message coming in
on a non-UI thread. It just complicates things when the implementation
of the callback interface on the client is on the UI object itself. You
are better off having a separate object on the client that derives from
MBRO and then exposes events that other objects can respond to. Any
calls from the server to the client which result in updating the UI will
have to be marshaled from the callback to the UI thread.

Regarding the server and the client being tightly bound, this is no
more the case than when you use events. Yes, the server has a reference
to the client, but with events, the same thing occurs.

If the client goes away (in this case, the object implementing the
callback interface, or the server, for that matter, since they both
derive from MBRO), then the lease will expire, and the proxy on the
other end will be invalidated.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)


Hi Nicholas

Thanks for the reply. I think I have half done what you suggest
already. I have a class in the server that inherits from
MarshalByRefObject. I create an instance of that in the client, and
then use it to sink events raised by the server. By passing this object
to the server on which to raise its events, it seems that the server
and client would be quite tightly bound together though. If the client
goes away without telling the server (crashes), the server would try to
raise events on an object that doesn't exist, but where the reference
is not nothing. Then what would happen?

I'm not sure that solution gets over the UI thread issue either. The
event will always be on the wrong thread until it is marshalled to the
right thread, or BeginInvoke is used. I think I would have to do that
in any case.

Charles


"Nicholas Paldino [.NET/C# MVP]" <[email protected]>
wrote in message Charles,

I would recommend against using an event in this situation.
Rather, have a shared interface which represents the callback from the
server to the client, and then implement an instance of that object on
the client side, making sure the class derives from
MarshalByRefObject. Then, expose a method on the service which takes
an instance of this implementation and pass your MarshalByRefObject to
that method on the service.

This allows the service to call back into the client. Then, you
can have that object raise events which other classes can respond to.
I don't recommend calling back directly to say, the UI, because the
calls will come in on threads other than the UI thread.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

I've read numerous articles and bits of code that purport to do this,
but I think there is a gap somewhere (quite possibly in my head).

I have a server, which is actually a Windows service. I also have a
client that needs to retrieve information from this service, but also
needs to receive events from it, when it (the client) is running.
I've done all the MBO stuff, and the client can pick up info from the
server at will. That was the easy bit.

Now, I want the service/server to be able to raise an event, and the
client to handle it. The sticking point seems to be: How do I raise
the event in the server? It seems to me that in order to do that I
need a reference to the MBO on which the event is to be raised. In my
server I have

Dim identifier As String = "MyServer"
Dim mode As WellKnownObjectMode = WellKnownObjectMode.Singleton
Dim entry As WellKnownServiceTypeEntry
entry = New WellKnownServiceTypeEntry(GetType(MyServerMBO),
identifier, mode)
RemotingConfiguration.RegisterWellKnownServiceType(entry)

But how do I get a reference to the MyServerMBO that is created?

I have tried making everything Shared, so that I don't need a
reference, but although I can see the RaiseEvent call being made, the
debugger steps right over it, indicating that there is nothing
attached to it, and the client never receives a call.

Have I missed something here?

TIA

Charles
 
Back
Top