?
Solved

Remoting and event delegation

Posted on 2003-03-02
11
Medium Priority
?
302 Views
Last Modified: 2008-03-10

I have a simple client/server application set up which uses an event wrapper to notify the client when something happens on the server.

Basically, a remote event wrapper object is set up, it is added to the relevant server method, then the client adds one of its events on to it as well - when the server method calls, it calls the event wrapper, which calls the client event.

It is my understanding that this kind of setup allows the client to register any of its methods with the wrapper, not just static methods (but I'm not sure about this).

I'm passing strings along with the event, and all the events seem to fire along the chain fine.  I can show textboxes or add a message to the client ArrayList for messages.

But when I'm over a TCPConnection, I can't SET any of the client controls to reflect changes brought about by the event.  The whole client app just hangs.  This is where it is weird - if I use an HTTPConnection, everything works fine.

I'm only passing strings around, and I can't figure out why using a TCP connection should make a difference, as the string appears ok at the other end in the debugger.

Any ideas on what would cause the problem when using a TCPConnection?  Is it more likely a formatting issue or something about its speed that causes a race?

I can post code for this, but it's already got a lot too it, so let me know which piece in particular you'd like to see and I'll put it up.

Thanks
0
Comment
Question by:jbone_44
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 4
11 Comments
 

Author Comment

by:jbone_44
ID: 8054299
I was wrong - the Http connection doesn't seem to really work either.  I think theres something going on in the remoting itself, so here is a skeleton of the code:


public class Client : System.Windows.Forms.Form
{

     Server server
     EventWrapper wrapper

     //other init stuff

     ArrayList messages

. . .

     public void GetServerConn()
     {
          HttpChannel channel = new HttpChannel(0);
          ChannelServices.RegisterChannel(channel);
          server = null;
          server = (Server)Activator.GetObject(
               typeof(Server),
               "http://localhost:2112/Server");
          if (server == null)
               MessageBox.Show("no server available");
         
          wrapper = new EventWrapper();
          wrapper.OnMessage += new MessageHandler(HandleMessage);
          server.UpdateClients += new                
                    MessageHandler(wrapper.HandleMessage);
     }

     public void HandleMessage(string message)
     {
          MessageBox.Show(message);
          Update(message);
          MessageBox.Show(message);
     }
     
     public void Update(string message)
     {
          //this is where we have problems
          orders.Add(message);
          textBox1.AppendText(message);
     }

     private void btn1_Click(object o, EventArgs e) {
          server.sendMessage(textBox1.Text);
     }
. . .

}

public class Server : MarshalByRefObject
{

. . .

     public event MessageHandler UpdateClients;

     public void sendMessage(string message)
     {    
          UpdateClients(message);
     }
. . .
}

public delegate void MessageHandler(string message);

public class EventWrapper : MarshalByRefObject
{
     public event MessageHandler OnMessage;

     public void HandleMessage(string message)
     {
          OnMessage(message);
     }

}

Any help appreciated
0
 

Author Comment

by:jbone_44
ID: 8054302
"orders" in the Update function should read "messages" - typo
0
 
LVL 10

Expert Comment

by:smegghead
ID: 8056406
do you have a copy of the 'server' dll in the same directory at the client app ??
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 3

Accepted Solution

by:
Sijin earned 200 total points
ID: 8057218
Well you are handling the problem of remoting events correctly by using a wrapper class that is MarshalByRef, but the thing is that in Update() method you are trying to update controls from a thread that did not create the control and this has unpredictable behaviour.

You will have to use the Invoke() method of the Control to update the controls. Look in the SDK documentation for the Invoke method.

From SDK documentation

Controls in Windows Forms are bound to a specific thread and are not thread safe. Therefore, if you are calling a control's method from a different thread, you must use one of the control's invoke methods to marshal the call to the proper thread.

There are four methods on a control that are safe to call from any thread: Invoke, BeginInvoke, EndInvoke and CreateGraphics. For all other method calls, you should use one of these invoke methods when calling from a different thread



Windows Forms uses the single-threaded apartment (STA) model because Windows Forms is based on native Win32 windows that are inherently apartment-threaded. The STA model implies that a window can be created on any thread, but it cannot switch threads once created, and all function calls to it must occur on its creation thread. Outside Windows Forms, classes in the .NET Framework use the free threading model. For information about threading in the .NET Framework, see Threading.

The STA model requires that any methods on a control that need to be called from outside the control's creation thread must be marshaled to (executed on) the control's creation thread. The base class Control provides several methods (Invoke, BeginInvoke, and EndInvoke) for this purpose. Invoke makes synchronous method calls; BeginInvoke makes asynchronous method calls.



Read up a bit more on Invoke and modify your Update method to use the Invoke methods and you should be ok.

Hope this helps.
0
 

Author Comment

by:jbone_44
ID: 8058960
thanks - although i haven't tried it yet, that sounds consistent with what im seeing.

i will give it a shot and let you know -

also - do you know if I can invoke the whole update method, or do I need to Invoke each of the controls I want to update?
0
 
LVL 10

Expert Comment

by:smegghead
ID: 8058976
You can just invoke a method which updates all of your controls.
0
 

Author Comment

by:jbone_44
ID: 8060009
ok, I'm trying to figure out how to invoke on the control - do you have any examples of how i could do it if i wanted all the controls of the form to be updated when the update method was called?

in other words, i would like to run invoke on the update method, and not have to do so on each of the controls.

is this possible/do you have example?
0
 

Author Comment

by:jbone_44
ID: 8060381
it looks like i spoke too soon - i tried this out

public void Update(string message)
{
//this is where we have problems
     messages.Add(message);
     UpdateDataGridDelegate dlg = new UpdateDataGridDelegate(UpdateDataGrid);
     c1FlexGrid1.Invoke(dlg);
}

public void UpdateDataGrid()
{
     c1FlexGrid1.DataSource = null;
     c1FlexGrid1.Refresh();
     c1FlexGrid1.DataSource = messages;
     c1FlexGrid1.Refresh();
}

it just hangs!!!! it will finally do what its supposed to when i right click on it in the taskbar (like it kicks into gear or something), but suffice to say the program is not behaving well with this code in it.  what am i doing wrong?
0
 

Author Comment

by:jbone_44
ID: 8061118
ok, (this is becoming a diary) the problem appears to be that im calling the remote server directly - the client thread that needs to update the grid isn't free because its still waiting for server method to return

i changed this and now the client executes the server method asynchronously.  it never uses EndInvoke to check the result, but im thinking thats ok???  is that something i need to deal with?
0
 
LVL 10

Expert Comment

by:smegghead
ID: 8061127
try just saying

this.Invoke(dlg);

rather than

c1FlexGrid1.Invoke(dlg);

Also, what does 'messages.add' do??? ensure that it's nothing on the GUI thread.
0
 
LVL 10

Expert Comment

by:smegghead
ID: 8061145
you only use EndInvoke if you used BeginInvoke... Invoke on it's own is fine.
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article describes a simple method to resize a control at runtime.  It includes ready-to-use source code and a complete sample demonstration application.  We'll also talk about C# Extension Methods. Introduction In one of my applications…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question