yohannist
yohannist

Reputation: 4204

Adding the result of a C# asynchronous DNS address resolution operation to a UI Element

I am trying to asynchronously resolve an IP address to host name using C# and then add the result to a ListBox. The asynchronous operation works alright but i can not add the resolved name to a listbox because another thread owns it. How can i bypass this issue and add the resolved name to a listbox.

here is what i've done so far

public static ManualResetEvent GetHostEntryFinished = new ManualResetEvent(false);            

            private void AsyncDNSResolver(string IPString)
        {
        GetHostEntryFinished.Reset();

        IPHostEntry host = new IPHostEntry();
        host.AddressList = new IPAddress[] { IPAddress.Parse(IPString) };
        Dns.BeginGetHostEntry(host.AddressList[0], new AsyncCallback(GetHostEntryCallback), host);

        GetHostEntryFinished.WaitOne();

    }

    public static void GetHostEntryCallback(IAsyncResult ar)
    {
        IPHostEntry host = (IPHostEntry)ar.AsyncState;
        while (!ar.IsCompleted) ;
        host = Dns.EndGetHostEntry(ar);
       lsvHosts.items.add(host.HostName);
     GetHostEntryFinished.Set();
    } 

Upvotes: 0

Views: 1695

Answers (2)

Kane
Kane

Reputation: 16812

If you wanted to execute an expensive activity on a separate thread and continue working while waiting for the result you can use this code snippet.

static void Main(string[] args)
{
    Console.WriteLine("About to call DNS");
    ResolveDnsAndPerformWorkWhileWaiting("74.125.237.112");
    Console.Read();
}

public static void ResolveDnsAndPerformWorkWhileWaiting(string ipaddress)
{
    var task = new Task<string>(() =>
        {
            var host = new IPHostEntry { AddressList = new[] { IPAddress.Parse(ipaddress) } };
            var result = Dns.GetHostEntry(host.AddressList[0]);
            return result.HostName;
        });

    // execute the work on another thread
    task.Start();

    // do other stuff

    // use the results (if the task has not finished the .Result property will hold until completed)
    var resolvedAddress = task.Result;
    Console.WriteLine("Resolved address:" + resolvedAddress);
}

If you are using a Windows Forms application then the easiest way would be to use a BackgroundWorker, here is a code sample

static void Main(string[] args)
{
    Console.WriteLine("About to call DNS");

    var worker = new BackgroundWorker();
    worker.DoWork += worker_DoWork;
    worker.RunWorkerCompleted += worker_RunWorkerCompleted;
    worker.RunWorkerAsync("74.125.237.112");


    Console.Read();
}

static void worker_DoWork(object sender, DoWorkEventArgs e)
{
    var host = new IPHostEntry { AddressList = new[] { IPAddress.Parse((string)e.Argument) } };
    var result = Dns.GetHostEntry(host.AddressList[0]);

    e.Result = result.HostName;
}

static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // You could set your UI control here like label1.text = (string)e.Result
    Console.WriteLine((string)e.Result);
}

Upvotes: 1

Richard Szalay
Richard Szalay

Reputation: 84784

The intention is that you would continue execution from GetHostEntryCallback (which could be anonymous within AsyncDNSResolver) and raise another event to return the data to the caller. This the nature of the asynchronous programming model available to you (pre-C# 5). In this case, AsyncDNSResolver cannot return string because it won't be available by the time it exits.

Your choice comes down to:

  1. Embrace async by raising an event (or calling another callback), rather than attempting to return string from AsyncDNSResolver
  2. Stop using the async method and use the blocking Dns.GetHostEntry instead.

Upvotes: 1

Related Questions