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

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

Thanks alot Sknake, thats very kind of you!

I have made a new skinny project which should show the problem.

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 meeting, networking, learning, and sharing knowledge.