अजपा योग क्रिया आणि ध्यान : श्वास, मंत्र, मुद्रा आणि ध्यान यांच्या सहाय्याने मनःशांती, एकाग्रता, चक्र संतुलन आणि कुंडलिनी जागृती. अधिक माहिती आणि आगामी तारखांसाठी येथे जा.


Utilize Server Sent Events in ASP.NET MVC

Some web applications application need to show data in real-time. As soon as the data is made available at the server, it immediately needs to be displayed to the end user. Traditionally developers used to poll the server periodically to check if a new data is available. This approach has its own drawbacks and may prove to be unsuitable in certain cases. Wouldn't it be nice if server notifies the client of new data rather than client checking with the server periodically? That is what HTML5 Server Sent Events (SSE) allow you to do. In this article you will learn what HTML5 Server Sent Events are and how to develop a ASP.NET MVC application that receives real-time data from the server.

Ajax polling vs. SSEs

Web applications that need to display real-time data often use "polling" techniques to fetch the latest data from the server. For example, you may develop an ASP.NET web form that makes Ajax requests to the server periodically to check whether new data is available. Accordingly the web form renders itself showing the latest data. However, such techniques have their own drawbacks including:

  • Polling techniques make too many requests to the web server if the frequency of polling is too short. This causes burden on the server.
  • Since polling operations are performed by the client there is no way to tell the client whether new data is really available on the server. A client may keep polling the server periodically even if there is no data available. This is unnecessary overhead on the overall system.
  • Polling technique is less accurate. Since polling frequency is decided by the client and is independent of server side data availability it may so happen that data is available on the server now but the client is able to show the new data after some time gap.

The Server Sent Events or SSEs are dispatched by the server. Using SSE you can notify the client application whenever something interesting (say availability of new data) happens on the server. The client can then take appropriate action (say displaying the new data to the user).

Example using SSE with ASP.NET MVC Controller

To understand how SSEs can be used in ASP.NET MVC application you will develop an application as shown below:

The application has a view with Start Listening button. Clicking on this button causes the browser to open a connection with a specified Event Source. The event source is responsible to send the notification data back to the browser. Once the even source sends the data the connection to the event source is closed.

Begin by creating a new ASP.NET MVC project and add HomeController to it. In addition to the Index() action, the HomeController will have an action that acts the event source. This action - Process() - is shown below:

public ActionResult Process()
{
    StringBuilder sb = new StringBuilder();
    using (Northwind db = new Northwind())
    {
        foreach (Customer obj in db.Customers)
        {
            string jsonCustomer = JsonConvert.
                                  SerializeObject(obj);
            sb.AppendFormat("data: {0}\n\n", jsonCustomer);
        }
    }
    return Content(sb.ToString(), "text/event-stream");
}

The Process() action creates a StringBuilder for storing the data that is to be sent back to the browser. The for loop simply iterates through the Customers DbSet and grabs an individual Customer object. This Customer object is converted to its JSON representation using Json.Net component's JsonConvert class. The SerializeObject() method accepts a .NET object and returns its JSON equivalent. The JSON data thus obtained is pushed into the StringBuilder object. Notice how the data is pushed into the StringBuilder. It's data followed by a : and then followed by a JSON object. The \n\n at the end indicates end of the data (a single Customer object in this case).

Also notice how the data is returned from the Process() action. The Content() method of the Controller base class takes two parameters - data to be send to the browser and its Content-Type. The data comes from the StringBuilder. The Content-Type is specified as text/event-stream. This content type is required for the proper functioning of SSEs.

This completes the server side code. Let's shift our attention to the client side code.

The Index view consists of a simple form as shown below:

<form>
    <input type="button" id="btnListen" 
           value="Start Listening" />
    <br /><br />
    <div id="headerDiv" class="tickerheading"></div>
    <div id="targetDiv" class="ticker"></div>
    <div id="footerDiv" class="tickerfooter"></div>
</form>

The form contains the Start Listening button and three <div> elements. The headerDiv displays the header message, the footerDiv displays the footer message and the targetDiv displays the data returned by the server.

The jQuery code that implements SSE in the Index view is shown below:

$(document).ready(function () {

    $("#btnListen").click(function () {

        var source = new EventSource('/home/process');

        source.addEventListener("open", function (event) {
            $('#headerDiv').append
             ('<h1>Processing started...</h1>');
        }, false);


        source.addEventListener("error", function (event) {
            if (event.eventPhase == EventSource.CLOSED) {
                $('#footerDiv').append
                 ('<h1>Connection Closed!</h1>');
                source.close();
            }
        }, false);

        source.addEventListener("message", function (event) {
            var data = JSON.parse(event.data);
            $("#targetDiv").append
             ("<div>" + data.CustomerID + 
              " - " + data.CompanyName + "</div>");
        }, false);

    });
});

The code consists of four pieces.

  • In the click event handler an EventSource is created pointing to /home/process. Thus EventSource object will attempt to open a connection to this specified resource.
  • If the connection is opened successfully, the open event is raised by the EventSource object. The open event can be handled using the addEventListener() method. The open event handler simply displays a message in the headerDiv.
  • If there is any error while communicating the error event is raised. Inside, you can check the eventPhase and take appropriate action. In this case the code checks whether the underlying event source has been closed. If so it displays a message in the footerDiv and also calls the close() method of the EventSource. If you don't call the close() method the browser will again trigger the source after three seconds. Calling close() ensures that browser doesn't repeatedly trigger the event source. Of course, if you wish to have such repeated triggering, you shouldn't close the event source.
  • When the server sends event notification to the browser the message event is raised. The message event handler retrieves the data using the event.data property. In this case event.data will be a single Customer object in JSON format. And message will be raised multiple times depending on the data being sent from the server. The CustomerID and CompanyName are then appended to the targetDiv element.

If you run the application, you should get an output similar to the figure shown earlier.

Dealing with lengthy server side processing

So far so good. In the above example, the server side processing was quite straightforward. However, at times the server side processing might be quite lengthy and a lot of data might need to be sent to the client. In such cases, rather than waiting for the computation of all the data it would be better to send data in small chunks (say one Customer at a time). This way the client will receiving something from the server even if the server side processing is yet to complete. If you wish to accomplish such a task you can modify the Process() action like this:

public void Process()
{
    Response.ContentType = "text/event-stream";
    using (Northwind db = new Northwind())
    {
        foreach (Customer obj in db.Customers)
        {
            string jsonCustomer = JsonConvert.
                         SerializeObject(obj);
            string data = $"data: {jsonCustomer}\n\n";
            System.Threading.Thread.Sleep(5000);
            Response.Write(data);
            Response.Flush();
        }
        Response.Close();
    }
}

In this case instead of using the Content() method to return the ActionResult, the code uses Response object. The ContentType property of the Response is set to text/event-stream. A for each loop iterates through all the Customer objects. A Customer is converted into its JSON representation as before and written to the Response stream using Write() method. The Flush() methods of Response ensures that the data is flushed to the browser. The Close() closes the Response stream thus terminating the event source. Note that in the above code a delay of 5000 milliseconds is introduced to mimic some lengthy processing.

If you run the modified application, you will observe that a Customer is displayed after every five seconds instead of displaying all the customers at a time.

That's it for now! Keep coding !!


Bipin Joshi is an independent software consultant and trainer by profession specializing in Microsoft web development technologies. Having embraced the Yoga way of life he is also a meditation teacher and spiritual guide to his students. He is a prolific author and writes regularly about software development and yoga on his websites. He is programming, meditating, writing, and teaching for over 27 years. To know more about his ASP.NET online courses go here. More details about his Ajapa Japa and Shambhavi Mudra online course are available here.

Posted On : 02 May 2016