I have a service that performs a slow task, when it is finished, I want to update the client using AJAX with the result of the task. In my client, I call the task many times to update the results grid. For purposes of understanding, this is a connection tester that iterates over the list of connections to see if they are alive.
I implemented the service as WCF. I generate async methods when I add a service link to my web client.
The code works fine, but the screen locks instantly when callbacks fire - I think this happens because they all happen one after another, and they all quickly redraw the GridView. I do not want this glitch to occur. I was hoping that the AJAX implementation would be able to partially update the GridView as the results are returned from the service via callbacks.
The only way I can do this is to start asynchronous calls in a separate client thread, and then use a timer to redraw the data to the grid (the same data that is updated in a separate thread through callbacks).
I am doing this mini-project as a training exercise, then I want to do the same with MVC3 to find out the differences.
A snippet of code (without a separate thread, which slows down the display of the screen during the callback):
//get list of connections from session ConnectionList myConns = Session[SESSION_ID] as ConnectionList; //pass into async service call GetAllStatusAsync(myConns); protected void GetAllStatusAsync(ConnectionList myConns) { Service1Client myClient = new WcfConnectionServiceRef.Service1Client(); myClient.AsyncWorkCompleted += new EventHandler<AsyncWorkCompletedEventArgs>(myClient_AsyncWorkCompleted); foreach (ConnectionDetail conn in myConns.ConnectionDetail) { //this call isnt blocking, conn wont be updated until later in the callback myClient.AsyncWorkAsync(conn); } } //callback method from async task void myClient_AsyncWorkCompleted(object sender, AsyncWorkCompletedEventArgs e) { ConnectionDetail connResult = e.Result; //get list of connections from session ConnectionList myConns = Session[SESSION_ID] as ConnectionList; //update our local store UpdateConnectionStore(connResult, myConns); //rebind grid BindConnectionDetailsToGrid(myConns); }
Question: can this be done better in asp.net/AJAX? (In order to avoid problems with rendering blocking and partially get a mesh update as the results arrive), I really do not want to use a separate client stream, for example the following fragment:
// Perform processing of files async in another thread so rendering is not slowed down // this is a fire and forget approach so i will never get results back unless i poll for them in timer from the main thread ThreadPool.QueueUserWorkItem(delegate { //get list of connections from session ConnectionList myConns = Session[SESSION_ID] as ConnectionList; //pass into async service call GetAllStatusAsync(myConns); });
UPDATE:
Adding page layout on demand:
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="ASForm.aspx.cs" Inherits="Web_Asp_FBMonitor.ASForm" Async="true" EnableSessionState="True" %> <asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server"> </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> ASP.NET Connection Test (Client in ASYNC, Server in ASYNC) </h2> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <p> <%--This update panel shows the time, updated every second--%> <asp:UpdatePanel ID="UpdatePanel2" runat="server"> <ContentTemplate> <h3> <asp:Label ID="LabelTime" runat="server" Text=""></asp:Label> </h3> <asp:Timer ID="Timer1" runat="server" Interval="1000" ontick="Timer1_Tick"> </asp:Timer> </ContentTemplate> </asp:UpdatePanel> </p> <p> <%--This update panel shows our results grid--%> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <asp:GridView ID="GridView1" runat="server"> </asp:GridView> <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Default.aspx">Client Sync Page</asp:HyperLink> <br /> <asp:Button ID="ButtonUpdate" runat="server" Text="Update" onclick="ButtonUpdate_Click" /> </ContentTemplate> </asp:UpdatePanel> </p> </asp:Content>
UPDATE 2:
I am looking for a client side JS example. The received options are good and were highly appreciated, but the client JS is the one with which I am confused with my own inexperience and will reward this award.