Making Asynchronous Calls to WCF Services from ASP.NET

Posted by: Suprotim Agarwal , on 11/30/2008, in Category ASP.NET
Views: 138578
Abstract: In this article, we will see how to create a WCF service and then consume it asynchronously using ASP.NET. Asynchronous tasks can be performing using AddOnPreRenderCompleteAsync or RegisterAsyncTask methods of the Page class.
Making Asynchronous Calls to WCF Services from ASP.NET
 
When ASP.NET receives a synchronous request, it assigns a thread to the request from a thread pool. The thread remains blocked till the request is completed. Since the thread pool has got a limited number of threads, time consuming operations like pulling data from database can bring down the performance of the application. If there are multiple such time consuming operations, the scalability can go in for a toss.
ASP.NET 2.0 and above makes it simple to create Asynchronous pages. Unlike the synchronous operation, a thread is fetched from the pool but is returned back to the pool when the async operation begins. When the async operation completes, a thread is again grabbed from the pool to complete the process. This means that threads do not have to remain occupied for time consuming operations, thereby increasing the scalability of the application.
I had recently written an article to Access an AJAX Enabled WCF Service using ASP.NET and Client Script. A dotnetcurry.com user mailed back asking if there was a way to call a WCF service asynchronously. In this article, we will see how to create a WCF service and then consume it asynchronously using ASP.NET. Asynchronous tasks can be performing using AddOnPreRenderCompleteAsync or RegisterAsyncTask methods of the Page class. We will be using the RegisterAsyncTask in this example. Follow these steps:
Step 1: Create an ASP.NET 3.5 website
Right click Project > Add New Item > WCF Service > Type name as ‘NorthwindService.svc’ > Add.
Northwind service
For simplicity sake, I have not hosted the service on IIS. I am using the server that comes built-in with Visual Studio 2008. The server automatically allocates a port number. If you would like to keep the port number fixed, Select the project in the Solution Explorer > Go to the Properties window > Set 'Use Dynamic Ports' to False > Set the Port number. I am using port 64258. Build the Solution.
Step 2: We will query the 'Products' table in the Northwind database and return a list of Product names. We will create a Product class for this purpose. Now C# 3.0/ VB 9.0 introduce features like the ‘Anonymous type’ to cut down on the code required to create and instantiate a class using ‘the old way’. However, I prefer creating a class in case I need to pass in the result to a webservice or to a different part of your application. Right click the project > Add > Class > we will call our class ‘Products’
C#
///<summary>
/// Summary description for Products
///</summary>
public class Products
{
    public Int32 ProductID { get; set; }
    public string ProductName { get; set; }   
}
 
VB.NET
Public Class Products
      Private privateProductID As Int32
      Public Property ProductID() As Int32
            Get
                  Return privateProductID
            End Get
            Set(ByVal value As Int32)
                  privateProductID = value
            End Set
      End Property
      Private privateProductName As String
      Public Property ProductName() As String
            Get
                  Return privateProductName
            End Get
            Set(ByVal value As String)
                  privateProductName = value
            End Set
      End Property
End Class
Step 3: In your web.config, create <connectionStrings> section as shown below:
      <connectionStrings>
            <add name="NorthwindConnectionString" connectionString="Data Source=(local);Initial Catalog=Northwind;Integrated Security=True"/>
      </connectionStrings>
Step 4: Now move to the ServiceContract in the INorthwindService.cs or .vb file and replace the DoWork() method with ProductList() method as shown below:
C#
[ServiceContract]
public interface INorthwindService
{
      [OperationContract]
      List<Products> ProductList();
}
VB.NET
<ServiceContract> _
Public Interface INorthwindService
      <OperationContract> _
      Function ProductList() As List(Of Products)
End Interface
Go back to your NorthwindService.cs or vb and implement the ProductList() method. Write the following code:
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Activation;
using System.Data;
using System.Data.SqlClient;
 
 
// NOTE: If you change the class name "NorthwindService" here, you must also update the reference to "NorthwindService" in Web.config.
 
public class NorthwindService : INorthwindService
{   
    public List<Products> ProductList()
    {
        string nwConn = System.Configuration.ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
        var prodList = new List<Products>();
        using (SqlConnection conn = new SqlConnection(nwConn))
        {
            const string sql = @"SELECT ProductID, ProductName FROM Products";
            conn.Open();
            using (SqlCommand cmd = new SqlCommand(sql, conn))
            {
                SqlDataReader dr = cmd.ExecuteReader(
                    CommandBehavior.CloseConnection);
                if (dr != null)
                    while (dr.Read())
                    {
                        var prods = new Products
                        {
                            ProductID = dr.GetInt32(0),
                            ProductName = dr.GetString(1)                           
                        };
                        prodList.Add(prods);
                    }
                // Simulating a delayed asynchronous task.
 
                System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5.0));
 
                return prodList;
            }
        }
    }
 
}
 
VB.NET
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Runtime.Serialization
Imports System.ServiceModel
Imports System.Text
Imports System.ServiceModel.Activation
Imports System.Data
Imports System.Data.SqlClient
 
 
' NOTE: If you change the class name "NorthwindService" here, you must also update the reference to "NorthwindService" in Web.config.
 
Public Class NorthwindService
      Implements INorthwindService
      Public Function ProductList() As List(Of Products)
            Dim nwConn As String = System.Configuration.ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString
            Dim prodList = New List(Of Products)()
            Using conn As New SqlConnection(nwConn)
                  Const sql As String = "SELECT ProductID, ProductName FROM Products"
                  conn.Open()
                  Using cmd As New SqlCommand(sql, conn)
                        Dim dr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
                        If dr IsNot Nothing Then
                              Do While dr.Read()
                                    Dim prods = New Products With {.ProductID = dr.GetInt32(0), .ProductName = dr.GetString(1)}
                                    prodList.Add(prods)
                              Loop
                        End If
                        ' Simulating a delayed asynchronous task.
 
                        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5.0))
 
                        Return prodList
                  End Using
            End Using
      End Function
 
The code shown above connects to the Northwind database and pulls the list of ProductID and ProductName from the Products table. The return type is a List<> of type Products. You can test this service by right clicking the NorthwindService.svc > View in Browser.
View Service
Click the WSDL (http://localhost:64258/ASPWCFAsync/NorthwindService.svc?wsdl) to view the operations and bindings.
Call this WCF Service asynchronously using ASP.NET
Once the WCF Service has been created, it’s time to consume this service asynchronously using ASP.NET. Follow these steps:
Step 5: Right click Project > Add Service Reference > Enter the url where the service is running ‘http://localhost:64258/ASPWCFAsync/NorthwindService.svc’ > Click the Go button and the service will be displayed as shown below along with the operations it supports.
Add Service
I have renamed the Namespace field as ‘ProductReference’. Click on the ‘Advanced’ button and check the checkbox ‘Generate asynchronous operations’ > Click OK.
Advanced Setting
Click OK again to add the Service Reference.
You will observe that a new folder called ‘App_WebReferences’ gets created which contains class and methods to call the service.
Step 6: Let’s now write some code to consume the service asynchronously. Go to the Default.aspx page. The first step is to add ‘Async=true’ to the Page directive as shown below. Setting the Async attribute on the page directive to 'true' avoids the thread executing the page to be blocked until the async tasks are completed.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Async="true" Inherits="_Default" %>
Now drag and drop a Button control and a ListBox to the page. Generate a Click event handler for the button and in the click event, write the following code:
C#
    protected void Button1_Click(object sender, EventArgs e)
    {
        PageAsyncTask pat = new PageAsyncTask(BeginProductRetrieveAsync, EndProductRetrieveAsync, null, null);
        Page.RegisterAsyncTask(pat);       
    }
 
    IAsyncResult BeginProductRetrieveAsync(object sender, EventArgs e, AsyncCallback acb, object extraData)
    {
        nor = new ProductReference.NorthwindServiceClient();
        return nor.BeginProductList(acb, extraData);
    }
 
    void EndProductRetrieveAsync(IAsyncResult ar)
    {
        var prods = new List<Products>();
        ListBox1.DataSource = nor.EndProductList(ar);
        ListBox1.DataTextField = "ProductName";
        ListBox1.DataValueField = "ProductID";
        ListBox1.DataBind();
    }
 
VB.NET
   Private nor As ProductReference.NorthwindServiceClient = Nothing
 
      Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs)
            Dim pat As New PageAsyncTask(AddressOf BeginProductRetrieveAsync, AddressOf EndProductRetrieveAsync, Nothing, Nothing)
            Page.RegisterAsyncTask(pat)
      End Sub
 
      Private Function BeginProductRetrieveAsync(ByVal sender As Object, ByVal e As EventArgs, ByVal acb As AsyncCallback, ByVal extraData As Object) As IAsyncResult
            nor = New ProductReference.NorthwindServiceClient()
            Return nor.BeginProductList(acb, extraData)
      End Function
 
      Private Sub EndProductRetrieveAsync(ByVal ar As IAsyncResult)
            Dim prods = New List(Of Products)()
            ListBox1.DataSource = nor.EndProductList(ar)
            ListBox1.DataTextField = "ProductName"
            ListBox1.DataValueField = "ProductID"
            ListBox1.DataBind()
      End Sub
We have used the PageAsyncTask class that contains information about an asynchronous task registered to a page. The parameters of the PageAsyncTask is as follows:
param1: handler to call when beginning an async task
param2: handler to call when task is completed successfully
param3: handler to call when the operation timeouts.
param4: object representing state of the task.
param5: bool representing if task can be processed in parallel with other async tasks.
Note: An Asynchronous task by default will time out if the operations does not complete within 45 seconds. You can specify your own time out using the Page directive <%@ Page AsyncTimeout="40" %>
A PageAsyncTask object must be registered to the page through the RegisterAsyncTask method. This is done using Page.RegisterAsyncTask(pat); 
The BeginProductRetrieveAsync and EndProductRetrieveAsync are the handlers that are called when beginning and completing an asyc task respectively. The ListBox is bound to the results in the EndProductRetrieveAsync handler.
Run the application. You will see that on the button click, a List of ProductName is fetched asynchronously from the WCF service. I would recommend users to read this article by Jeff Prosise where he has covered up Asynchronous Pages in detail. I hope you liked this article and I thank you for viewing it.
If you liked the article,  Subscribe to my RSS Feed or Subscribe Via Email

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Suprotim Agarwal, MCSD, MCAD, MCDBA, MCSE, is the founder of DotNetCurry, DNC Magazine for Developers, SQLServerCurry and DevCurry. He has also authored a couple of books 51 Recipes using jQuery with ASP.NET Controls and The Absolutely Awesome jQuery CookBook.

Suprotim has received the prestigious Microsoft MVP award for Sixteen consecutive years. In a professional capacity, he is the CEO of A2Z Knowledge Visuals Pvt Ltd, a digital group that offers Digital Marketing and Branding services to businesses, both in a start-up and enterprise environment.

Get in touch with him on Twitter @suprotimagarwal or at LinkedIn



Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by John Parlato on Sunday, November 30, 2008 7:02 AM
This is a very helpful article and I enjoyed learning from it, as I do much of what I find here.
Thanks .NetCurry.
Comment posted by Suprotim Agarwal on Sunday, November 30, 2008 8:13 PM
Thanks John :)
Comment posted by Thanigainathan.S on Thursday, December 4, 2008 3:46 AM
Hi,

We use ScriptManager and refer the service there also. Its makes more easy than this. Whats the difference between these two things.

Thanks & regards,
Thanigainathan.S
Comment posted by Shakti Singh Dulawat on Monday, January 12, 2009 3:07 AM
This is very nice article
Thanks for showing nice demo.

Regards
Shakti Singh Dulawat
<strong>http://www.nextmvp.blogspot.com/</strong>
Comment posted by Yami on Tuesday, January 20, 2009 7:37 PM
Hi,

I tried creating and running this sample aplication and I get the following error, Is there something that I am missing.
The Address property on ChannelFactory.Endpoint was null.  The ChannelFactory's Endpoint must have a valid Address specified.
Any thoughts on this is appreciated.
Thanks,
Comment posted by Suprotim Agarwal on Thursday, January 22, 2009 11:56 AM
Yami: See if this post helps:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/96c692f1-11b0-4ee0-b21f-03bc29e0800a/
Comment posted by Mark on Wednesday, February 11, 2009 6:05 AM
Very interesting example. I have one question: How do I access the data from the extraData object?

Let's say your ProductList() method had to take a parameter (list of a particular type of product, or all products below a certain cost). How would you implement that?

Comment posted by Mark on Wednesday, February 11, 2009 6:09 AM
Very interesting example. I have one question: How do I access the data from the extraData object?

Let's say your ProductList() method had to take a parameter (list of a particular type of product, or all products below a certain cost). How would you implement that?

Comment posted by vineet dubey on Tuesday, April 14, 2009 4:59 AM
Thanks to All. Can i make asynchronous call without specifying Page directive.In my application i have to send an email asynchronously. And my pages are inherited from some base pages.If i set directive on base page this will be by default set in all the decendents or childs.
Comment posted by vineet dubey on Thursday, April 16, 2009 6:44 AM
Can i make asynchronous call without specifying Page directive.In my application i have to send an email asynchronously. And my pages are inherited from some base pages.If i set directive on base page this will be by default set in all the decendents or childs
Comment posted by j on Tuesday, June 2, 2009 9:43 AM
asdf
Comment posted by pp on Tuesday, June 2, 2009 9:44 AM
nice article !!!!!!
Comment posted by chris on Monday, December 21, 2009 6:25 PM
Could you post the ProductReference.NorthwindServiceClient();? I get everything up to this point expect I don't see NorthwindServiceClient code after adding the reference.

Thanks
Comment posted by Bipul Tiwari on Tuesday, January 19, 2010 5:24 AM
Thanks for give nice article...........
Comment posted by Mahesh G on Monday, February 22, 2010 4:50 AM
Really helpful article.

Thanks for posting.
Comment posted by Prasanth on Tuesday, September 14, 2010 11:37 PM
hey Suprotim,

i have one small doubt,  async operation will be handled in seperate thread?, i am wondering if so will this thread will be from thread pool? could you clarify

Thanks
Comment posted by Pratheesh on Wednesday, September 15, 2010 11:02 AM
I am trying to implement the above code in my page load event but, it not working asynchronously. Which means page content is displayed only after the asynchronous event is completed. This is my code

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                ServiceReference1.Service1Client srv = new WebApplication1.ServiceReference1.Service1Client();
                srv.GetListCompleted += new EventHandler<WebApplication1.ServiceReference1.GetListCompletedEventArgs>(srv_GetListCompleted);
                srv.GetListAsync();

            }
        }

        void srv_GetListCompleted(object sender, WebApplication1.ServiceReference1.GetListCompletedEventArgs e)
        {
            lst1.DataSource = e.Result;
            lst1.DataBind();
            lst1.Visible = true;
        }

WCF Method

        public List<string> GetList()
        {
            List<string> myList = new List<string>();
            for (int rec = 0; rec < 1000; rec++)
            {
                myList.Add("testrec");
            }

            System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5.0));
            return myList;
        }
Comment posted by Zeeshan on Friday, November 12, 2010 1:56 AM
Sir I can't understand What is nor in step #6 While making Begin event????
Comment posted by fermion on Thursday, December 16, 2010 5:45 PM
Looks like nor is short for northwind, just as prods is short for products.

Async WCF is presumably better for windows forms based applications where as websites should probably use the UpdatePanel instead.
Comment posted by sundar on Monday, January 3, 2011 8:11 AM
In step #6, nor should be initialized as follows
ProductReference.NorthwindServiceClient nor = new ProductReference.NorthwindServiceClient();
Comment posted by Profet on Thursday, January 27, 2011 9:20 AM
******* [comment partly edited for being abusive] Before you publish your code you should check it another case later you will look stupid!
    protected void Button1_Click(object sender, EventArgs e)
    {
        PageAsyncTask pat = new PageAsyncTask(BeginProductRetrieveAsync, EndProductRetrieveAsync, null, null);
        Page.RegisterAsyncTask(pat);      
    }

    IAsyncResult BeginProductRetrieveAsync(object sender, EventArgs e, AsyncCallback acb, object extraData)
    {
        nor = new ProductReference.NorthwindServiceClient();
        return nor.BeginProductList(acb, extraData);
    }

    void EndProductRetrieveAsync(IAsyncResult ar)
    {
        var prods = new List<Products>();
        ListBox1.DataSource = nor.EndProductList(ar);
        ListBox1.DataTextField = "ProductName";
        ListBox1.DataValueField = "ProductID";
        ListBox1.DataBind();
    }
Where did you declare a variable "nor"?
For what you created a variable "prods"?

It is a big shame for MVP to make such stupid things!!!
Comment posted by Profet on Thursday, January 27, 2011 9:22 AM
Why did you hide your profile???!!!
Comment posted by Niro on Monday, October 3, 2011 10:31 PM
I have an issue on timeout for both Synchronous and Asynchronous call.

<binding name="BasicHttpBinding_IProductFacade" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:01:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="6291456" maxBufferPoolSize="524288" maxReceivedMessageSize="6291456" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">

<%@ Page AsyncTimeout="120" %>

I just want to leave the synchronous call to timeout of 1 minutes, but AsyncTimeout call to 2 minutes. Does it possible? If it's possible, what is the setting I'm missing, since I got timeout for both call after 1 min.

Comment posted by Saul Buendia on Wednesday, February 22, 2012 10:55 AM
Is there any post on how to implement this same approach into ASP.NET MVC3?
Comment posted by Nandish R Nelamane on Friday, June 22, 2012 12:12 AM
Can you help me, how to do the same in wpf application.If possible because i'm not getting solution any where for wpf + wcf so.
Comment posted by 12321 on Tuesday, October 2, 2012 12:46 AM
ertre213
Comment posted by lalit raghuvanshi on Wednesday, May 15, 2013 2:17 AM
Easiest way to create and consume WCF Services in asp.net
http://www.webcodeexpert.com/2013/04/how-to-create-and-consume-wcf-services.html
Comment posted by hemant kumar on Monday, November 11, 2013 12:54 AM
Asynchronous call to WebService / WCF using JQuery :
You can use JQuery.Ajax to call web service :
$.ajax({
type: Type, //GET or POST or PUT or DELETE verb
url: Uri, // Location of the service
// data: Data, //Data sent to server
dataType: DataType, //Expected data format from server

cache: false, // no-cache
success: function (msg) {//On Successfull service call
ServiceSucceeded(msg);
},
error: ServiceFailed// When Service call fails
});
Sample source code :
http://sharepoint.asia/asynchronous-call-to-web-services-using-jquery/