Hi.

I have this console based Asynchronous VS project that works fine.
And then i have a remoting project which also works fine. I want to edit the remoting project so it is non-blocking, using asynchronous calls.

I´ve tried different examples, but I cant get it to work. None of them seems to call my callback method back.

Here is the relevant snippets:

The remote object:

....
public class MultiContainer : MarshalByRefObject, IMultiContainer
    {
        public string GetClientsList()
        {
            Thread.Sleep(1000);
            return Program.ServerForm.GetClientsList();
        }
....

The client which accesses the remote object with asyn call:

namespace Client
{
    public partial class Form1 : Form
    {
        Server.IMultiContainer mc;
        private delegate string Delegate();

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            mc = new Server.MultiContainer();
            Delegate del = new Delegate(mc.GetClientsList);
            AsyncCallback callback = new AsyncCallback(Callback);
            del.BeginInvoke(callback, null);
        }

        private void Callback(IAsyncResult ar)
        {
            //this callback method is never called...
            Delegate del = (Delegate)((AsyncResult)ar).AsyncDelegate;
            richTextBox1.Text = del.EndInvoke(ar);
        }
...

Been sitting with this problem for hours, hope you can help!
Thanks alot :)

Recommended Answers

Maybe the delegate never finishes running.... Have you debugged it? This works:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting.Messaging;

namespace daniweb
{
  public partial class frmAsync : Form
  {
    private delegate string Delegate();

    public frmAsync()
    { …
Jump to Post

Create a new project and move enough of your code over to demonstrate the problem. At a glance your code looks OK. Upload your project here once you have moved the code. To upload you can click on "Go Advanced" then "Manage Attachments"

Jump to Post

Hello.
Isn't this non-stop recursive call to the same function:

public string GetClientsList()
        {
            try
            {
                Thread.Sleep(1000);
            }
            catch (Exception e1)
            {
                Console.writeline(e1.ToString());
            }
          return Program.ServerForm.GetClientsList();
        }
Jump to Post

All 11 Replies

Maybe the delegate never finishes running.... Have you debugged it? This works:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting.Messaging;

namespace daniweb
{
  public partial class frmAsync : Form
  {
    private delegate string Delegate();

    public frmAsync()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      List<string> clients = new List<string>();
      clients.Add("1");
      clients.Add("2");
      clients.Add("3");
      //This is a valid call
      
      new Func<string[], string>(DoWork).BeginInvoke(
        clients.ToArray(),
        new AsyncCallback(CleanupCallback),
        null);
      //This will throw an exception for demonstration purposes
      new Func<string[], string>(DoWork).BeginInvoke(
        default(string[]),
        new AsyncCallback(CleanupCallback),
        null);
    }



    private static string DoWork(string[] clients)
    {
      //clients will be null in one call, resulting in an exception. This is intended
      Console.WriteLine("Work beginning on " + clients.Length.ToString() + " clients.");
      System.Threading.Thread.Sleep(2000);
      return string.Join(", ", clients);
    }

    private static void CleanupCallback(IAsyncResult ar)
    {
      AsyncResult result = (AsyncResult)ar;
      Func<string[], string> action = (Func<string[], string>)result.AsyncDelegate;
      try
      {
        string returnValue = action.EndInvoke(ar);
        Console.WriteLine("finished : " + returnValue);
      }
      catch (Exception Ex)
      {
        Console.WriteLine("An error occured: " + Ex.Message);
      }
    }


  }
}

Results in:

A first chance exception of type 'System.NullReferenceException' occurred in daniweb.exe
Work beginning on 3 clients.
An error occured: Object reference not set to an instance of an object.
A first chance exception of type 'System.NullReferenceException' occurred in mscorlib.dll
finished : 1, 2, 3

The two red lines were output generate from the callback method. The code sample I posted also shows you how to get the exception, if any, that was thrown in your delegate method performing work.

Hi, and thank you for the answer!
Yes i have tried debugging it, and it doesent hang or anything, it just doesent call back.

I´ve tried to insert try catches like this:

The client:

private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                mc = new Server.MultiContainer();
                Delegate del = new Delegate(mc.GetClientsList);
                AsyncCallback callback = new AsyncCallback(Callback);
                del.BeginInvoke(callback, null);
            }
            catch(Exception e1)
            {
               Console.writeline(e1.ToString());
            }
        }

the object:

public string GetClientsList()
        {
            try
            {
                Thread.Sleep(1000);
            }
            catch (Exception e1)
            {
                Console.writeline(e1.ToString());
            }
          return Program.ServerForm.GetClientsList();
        }

.. but that returns nothing either.
Am i doing something wrong here?

Thanks alot for your time :)

Create a new project and move enough of your code over to demonstrate the problem. At a glance your code looks OK. Upload your project here once you have moved the code. To upload you can click on "Go Advanced" then "Manage Attachments"

Hello.
Isn't this non-stop recursive call to the same function:

public string GetClientsList()
        {
            try
            {
                Thread.Sleep(1000);
            }
            catch (Exception e1)
            {
                Console.writeline(e1.ToString());
            }
          return Program.ServerForm.GetClientsList();
        }
commented: probably :P good catch +5

Well it never ends in the catch, so I dont think so? :-/

Hello.
Isn't this non-stop recursive call to the same function:

public string GetClientsList()
        {
            try
            {
                Thread.Sleep(1000);
            }
            catch (Exception e1)
            {
                Console.writeline(e1.ToString());
            }
          return Program.ServerForm.GetClientsList();
        }

No it was running but the text was failing to set because of illegal cross-threading calls. This works:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Windows.Forms;

namespace RemoteAsyncTest
{
  public partial class Form1 : Form
  {
    private delegate string Delegate();
    Server.IMultiContainer mc;

    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      mc = new Server.MultiContainer();
      new Delegate(mc.GetClientsList).BeginInvoke(new AsyncCallback(Callback), null);
    }

    private void Callback(IAsyncResult ar)
    {
      System.Diagnostics.Debugger.Break(); //proves it is called
      Delegate del = (Delegate)((AsyncResult)ar).AsyncDelegate;
      string s = del.EndInvoke(ar);
      richTextBox1.Invoke(new MethodInvoker(
        delegate()
        {
          richTextBox1.Text = s;
        }
        ));
    }
  }
}

[edit]

Main Thread: Invokes delegate on another thread
Delegate Thread: runs delegate, runs callback (cant modify UI ctrls on this thread)

You only modify controls from the UI thread. This is accomplished by calling Control.Invoke() as above.
[/edit]

That worked :)
I still wonder though, why it didnt complain in compile or run time about the illegal cross threading.

Anyways, thanks alot Scott! :)

It did complain if you looked at your "Output" window in the IDE. As far as I know exceptions thrown from the thread pool are supressed by the runtime. If you manually create a thread and it raises an unhandled exception it will bring your entire application down -- and you can't stop it. So instead of bringing the application down they handle all exceptions from the threadpool in this case. You can re-raise the exception on the callback to "catch" it instead of wrapping your delegate in a try..catch, plus if you're calling a delegate from someone elses code you need a way to handle it. The framers thought of a brilliant way of using remoting to pass the exception to the callback so you don't have to create delegates to wrap delegates for exception handling ;)

Please mark this thread as solved if you have found an answer to your question and good luck!

One more tip -- You can use Action<> and Func<> to create anonymous delegates instead of declaring a new delegate that returns a string. Here is an example using your existing code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Windows.Forms;

namespace RemoteAsyncTest
{
  public partial class Form1 : Form
  {
    //private delegate string Delegate();
    Server.IMultiContainer mc;

    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      mc = new Server.MultiContainer();

      new Func<string>(mc.GetClientsList).BeginInvoke(new AsyncCallback(Callback), null);
    }

    private void Callback(IAsyncResult ar)
    {
      System.Diagnostics.Debugger.Break(); //proves it is called
      Func<string> del = (Func<string>)((AsyncResult)ar).AsyncDelegate;
      string s = del.EndInvoke(ar);
      richTextBox1.Invoke(new MethodInvoker(
        delegate()
        {
          richTextBox1.Text = s;
        }
        ));
    }
  }
}

I find that easier than declaring delegates all over the place.

Very useful, thanks alot!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts learning and sharing knowledge.