C# 5.0 Async Programming and Caller Information
Since the release of .Net 4.5 Framework there are new, very useful features added that I want you to get familiar with. Because the C# language evolves along the .Net Framework, I have created chart that will help you to see all major changes that have been introduced over the last 10 years. I still remember myself starting my programming adventure with VS 2002 🙂
Let’s focus on the new C# 5.0 features now.
Async Framework introduced in C# 5.0 will probably change the the way we do our programming on the .net platform. The idea is to apply standard async procedures in the background while allowing developer to minimize amount of code required.
The new Async logic seems to be incorporated into standard synchronous functions with only a few keywords added (eg. await, async). When marked async, methods are executed synchronously until the first await statement. At this same time the control is given back to the caller allowing executing thread to function correctly (will not freeze UI).
In our example we will call WCF service using async framework. This is mostly accurate real live scenario whether you will use windows forms or WPF application to boost user experience within the UI layer.
After our WCF service is started (self hosting) we are implementing code as follows.
private async void btnSendWCF_Click(object sender, EventArgs e) { Task<string> responseTask = SendWCFMessage("test message"); await Task.Delay(3000); //give it more time var response = await responseTask; txtResult.Text = response; }
After executing this methods we are awaiting for the responseTask result while main thread is returned to the caller and UI is fully responsive.
SendWCFMessage method returns task string result. We will use Factory.StartNew to wrap-up our WCF request and return it. See in-line comments.
Task<string> SendWCFMessage(string message) { return Task<string>.Factory.StartNew(() => { try { //use TCP when sending message on the same computer or within the trusted network var binding = new NetTcpBinding(); var endpoint = new EndpointAddress(hostEndPointAddress); var factory = new ChannelFactory<IServiceHost>(binding, endpoint); var channel = factory.CreateChannel(); //send entered message using created channel var result = channel.SendMessage(message); //Trace caller information TraceMessage(result); //return value from the task return result; } catch (Exception ex) { return ex.Message; } }); }
As a second example we will use WebRequest class and reuse existing async functionality – the methods GetResponseAsync and CopyToAsync. In both examples we will also display caller trace information.
private async void btnSendHttpReq_Click(object sender, EventArgs e) { var request = WebRequest.Create(txtUri.Text.Trim()); var content = new MemoryStream(); Task<WebResponse> responseTask = request.GetResponseAsync(); using (var response = await responseTask) { using (var responseStream = response.GetResponseStream()) { Task copyTask = responseStream.CopyToAsync(content); await Task.Delay(3000);//give it more time //wait until finished (release main thread in the meantime) await copyTask; } } txtResult.Text = string.Format("Response length {0}", content.Length); //Trace caller information TraceMessage(txtResult.Text); }
Please notice that in Caller Information “member name” is btnSendHttpReq_Click for webrequest and TraceMessage for WCF as the method is invoked from different thread.
I have attached project files below so you can do your tests as well.