Click here to Skip to main content
Click here to Skip to main content

HTTP Push from SQL Server — Comet SQL

By , 27 Nov 2012
 

Contents

Introduction

This article presents how to implement the functionality for presenting the so-called real-time data using ASP.NET and SQL Server. This functionality is realized by implementing Comet functionality in ASP.NET and connecting this with Query Notification from SQL Server.

Application Basic Idea

The code presented can also be used when adding a web interface to a legacy system based on SQL Server without changing the legacy system.

The presented code can also be used instead of periodical data refresh in existing web interfaces which use an ASP.NET AJAX Timer. After adaptation of my solution, data in the web browser will be refreshed only just after the data is updated in SQL Server. With no artificial delay. This is why I called it real-time data (not to be confused with Real-time computing).

Background

I wanted to implement a SQL Server initiated message to an Internet browser, but I wanted to do this without Java applets, without Flash, and without a Comet-dedicated server. Only JavaScript with AJAX. I also decided not to use advanced Comet message parsing on the client side. My Comet message contains only an event with simple information: "something was changed". I will later explain why I do it like this.

This article is not about periodical (for example, every 10 seconds) refresh of data from SQL Server or the page in a browser. In this case, the user will see updated information with a maximum delay of 10 seconds. This article is about cases when a compromise between small refresh time and server resources (CPU, RAM, network) can not be achieved. This article is about cases when a periodic refresh delay is too big, and you can not decrease this time because you will break down your server.

From Comet Idea to Implementation in ASP.NET

Comet Idea

Some ideas behind Comet and Comet implementation called Long Polling are described on Wikipedia. I can only add some UML diagram to visualize the idea.

Comet Idea

and the same using a loop:

Comet Idea - Loop

Long-lived HTTP Request

In the previous images, you can see that the Internet browser is notified by the WWW server. Using only pure HTTP without extensions (as those proposed in HTML 5 or similar), it is not simple. Internet browsers were not designed for receiving notifications from a server. We must use some workaround to get this notification.

One of the possibilities is to make some HTTP request and wait for a response. The server will not return a response until some event is raised.

Long HTTP Request Implementation of Comet - Impractical

When the client receives a response ("Notification" arrow), it means that the event was raised. This event is our Comet message.

This long-lived HTTP request to the server can be very long, maybe even infinite. Implementing this without introducing some timeout is impractical: think about fighting with all possible timeouts and with a "dead" request on the server because of a broken connection. Let us set some limits on how long the request can be...

Long Polling

To prevent network timeouts and other problems with infinite requests, instead of infinite waiting, we can wait long but not too long. In the case of a request waiting too long, a special response is generated telling the client that there is no notification and that it must request for a notification again.

Long Polling Implementation of Comet

This pair of "TOO LONG" response and "Request again" is repeated in a loop periodically. It prevents timeouts, and we can call it "Comet Keep-alive". The number of keep-alives, of course, can be 0 when an event comes before the first "TOO LONG" message.

Implementation of Long Polling Comet in ASP.NET

Parsing Comet messages and then using DOM manipulation on the page can not only be hard for JavaScript beginners (like me), it also moves some logic (logic of how the page looks like) from ASP.NET to JavaScript. I recognized it as undesirable because in this case, to change or add some content to the Comet message, you must also change how the Comet JavaScript will parse this message. Because of that reason, I decided to use Comet only for a simple notification that something has changed. After receiving this message, the client will refresh data by making a postback to the current ASPX page (see the "Refresh" and "Page" arrows).

Long Polling Implementation of Comet - Details

Long Polling in ASP.NET

Why not an ASP.NET AJAX Timer

ASP.NET AJAX Timer can be used for periodic page refresh (or partial page refresh). Instead of this, I decided to use asp:Timer to make the long-lived requests described and shown in the Long Polling paragraph. It worked fine and simple until I wanted to stop watching real-time refreshing and click some button. The postback sent by the button click was blocked. It was queued and executed after the long-lived "tick" from asp:Timer. Aborting the current postback (using the technique described in the "Canceling an Asynchronous Postback" article on MSDN) does not work as I needed: it "has no effect on what's going on in the server". See the "Canceling Server Tasks with ASP.NET AJAX" article on MSDN for details, or take a look at the "Cancelling Async Postback" thread on the ASP.net forum. If we use Session, our postback will be queued and executed after (still running) the cancelled postback!

OK, no more bad solutions. In the next paragraphs, I will show my implementation, describing arrow by arrow from the sequence diagram.

Page request - first arrow

The three first arrows are simple. The user enters the URL or clicks a link, and the page is generated with a GridView filled with data using DataBind(), and this page is returned to the client - nothing unusual.

private void RefreshData()
{
    // . . . 

    int lastRecId;
    List<string> data = MessageDal.GetMessageData(out lastRecId, ...);

    // . . .
    
    Session["LastRecId"] = lastRecId;
    GridView1.DataSource = data;
    GridView1.DataBind();
}

"HTTP Request for notification" arrow

The arrow described as "HTTP Request for Notification" is implemented in JavaScript using AJAX with jQuery. Using jQuery was much simpler for me (JavaScript beginner) than using XMLHttpRequest directly or using the Microsoft AJAX library.

When the page is loaded, the longPolling() function is called.

$(document).ready(function(){
    longPolling(); // Start the initial request 
});

The longPolling() function makes an AJAX request to CometAsyncHandler.ashx, IHttpAsyncHandler, which simulates some kind of a page, that is calculated as a very long time. This time is specified in seconds in the request parameter (i.e., waitTime=60).

function longPolling()
{
$.ajax({
    type: "GET",
    url: "CometAsyncHandler.ashx?waitTime=60", // one minute
    cache: false,
    success: function(data){ 
        isPolling--;
        if(data == "NEWDATAISAVAILABLE")
            RefreshData(); // this function is generated by
                           // using RegisterFunctionToPostBack()
        else if( data == "TOOLONG-DOITAGAIN" )
            setTimeout("longPolling()", 0 );
        else
            addLongPollingError("error",
                "Error on server side. Received data: \"" +
                data + " \"");
    },
    error: function(XMLHttpRequest, textStatus, errorThrown){
        isPolling--;
        addLongPollingError("error",
            textStatus + " (" + errorThrown + ")");
    }
});
}

This request is handled on the server side by the CometAsyncHandler class derived from IHttpAsyncHandler. On the ASP.NET server side, we check if there is new data. If we have new data, then an HTTP response is immediately generated with information: "NEWDATAISAVAILABLE". If there is no new data, then we register to receive Query Notifications (implemented in WaitMessageDataAsync()) and just wait for new data. (How the registration is made will be explained later.)

public class CometAsyncHandler : IHttpAsyncHandler, IReadOnlySessionState
{
    public static List<CometAsyncResult> AllWaitingClients =
        new List<CometAsyncResult>();
    public static object AllWaitingClientsSync = new object();
    private static bool threadForTimeoutsWorking = false;

    // . . .
    // . . .
    // . . .
    
    public IAsyncResult BeginProcessRequest(HttpContext context,
        AsyncCallback cb, object extraData)
    {
        context.Response.ContentType = "text/plain";

        // Get wait time from request
        int waitTime;
        ParseRequest(context.Request, out waitTime);

        // Get last seen record ID from Session
        int lastRecId = (int)context.Session["LastRecId"];

        // . . .

        CometAsyncResult result = new CometAsyncResult(
        context, cb, waitTime, lastRecId);
        lock (AllWaitingClientsSync)
        {
            // register to Query Notification or complete
            // request synchronously in case if there is
            // already new data:
            if (!MessageDal.WaitMessageDataAsync(lastRecId))
            {
                // if not waiting (there is new data)
                // result is to be completed synchronously
                result.IsCompleted = true;
                result.CompletedSynchronously = true;
                result.Result = true; // new data is available
                WriteResponseToClient(result);
                return result;
            }
            else
            {
                // asynchronous (normal case):
                AllWaitingClients.Add(result);

                if (AllWaitingClients.Count == 1)
                    StartClientTimeouter();
            }
        }
        return result;
    }
    
    // . . .
    // . . .
    // . . .
}

"TOO LONG" response

To prevent very long waiting (or infinite waiting), we create a "while" thread that checks all waiting (not responded) clients whether they are waiting too long. If a given client is waiting too long, it is removed from the list and the Callback() associated with the client is called. This callback is the AsyncCallback cb parameter from the BeginProcessRequest() method.

Following is a part of StartClientTimeouter() (modified for presentation and contains only the main idea):

while( AllWaitingClients.Count > 0)
{
    // Call Callback() to all timeouted requests and
    // remove from list.
    lock (AllWaitingClientsSync)
    {
        DateTime now = DateTime.Now;
        AllWaitingClients.RemoveAll(
            delegate(CometAsyncResult asyncResult)
                {
                    if (asyncResult.StartTime.Add(asyncResult.WaitTime) < now)
                    {
                        asyncResult.Result = false; // timeout

                        asyncResult.Callback(asyncResult);
                        return true; // true for remove from list
                    }

                    return false; // not remove (because not timed out)
                });
    }

    // This sleep causes that some timeouted clients are removed with delay
    // Example: if timeout=60s, sleep=1s then timeouted client can be removed after 60,7s.
    // In some cases this can be considered as bug. TODO: Change it to WaitOne() and
    // calculate proper sleep time.
    Thread.Sleep(1000); 
}

After calling Callback() (which is the same as the AsyncCallback cb parameter from the BeginProcessRequest() method), the EndProcessRequest() method is called by th ASP.NET framework. In this method, we have a chance to finish generating the HTTP response.

public void EndProcessRequest(IAsyncResult result)
{
    WriteResponseToClient((CometAsyncResult) result);
}

public void WriteResponseToClient(
    CometAsyncResult cometAsyncResult)
{
    if (cometAsyncResult.Result)
        cometAsyncResult.Context.Response.Write(
            "NEWDATAISAVAILABLE");
    else
        cometAsyncResult.Context.Response.Write(
            "TOOLONG-DOITAGAIN"); // timeout - client must make request again
}

So to each timed out client (time out thread sets its result to false), a "TOOLONG-DOITAGAIN" response is returned. This response is handled by the JavaScript code fragment that made the AJAX/Comet request.

    // . . . part of <a href="#longPollingFunction%22">longPolling()</a> function
    else if( data == "TOOLONG-DOITAGAIN" )
        setTimeout("longPolling()", 0 );
    // <a href="#longPollingFunction%22">. . .</a>

"Request again" arrow

The code above will cause that, after the "too long" message, the current function will be called again. This will cause the client to make the "HTTP Request for notification" once again.

"Notification" arrow

When a Query Notification comes from SQL Server to the ASP.NET server (see bold arrow), the ProcessAllWaitingClients() method is called. This method will iterate through the waiting clients list, setting the Result fields to true and calling the callback (passed earlier as a parameter to the BeginProcessRequest() method).

public static void ProcessAllWaitingClients()
{
    // . . . 
    foreach (CometAsyncResult asyncResult in AllWaitingClients)
    {
        asyncResult.Result = true; // New data available
        asyncResult.Callback(asyncResult);
    }
    AllWaitingClients.Clear();
    // . . .
}

The callback will execute EndProcessRequest() in the same way as in the case of the timed out thread. The difference lies in the fact that Result is set to true in this case. So during HTTP response generation, "NEWDATAISAVAILABLE" is written.

This response is handled by the same JavaScript code fragment that made the AJAX/Comet request.

// . . . part of <a href="#longPollingFunction%22">longPolling()</a> function
if(data == "NEWDATAISAVAILABLE")
    RefreshData(); // this function is generated
                   // by using RegisterFunctionToPostBack()
// <a href="#longPollingFunction%22">. . .</a>

In this case, the longPolling() function is not executed again, so the long polling loop is not stopped. Instead of complicated data, we only have information about new data.

Page Refresh

After receiving the Comet message, we make a partial AJAX refresh by sending a postback to asp:UpdatePanel (UpdatePanel1).

function RefreshData()
{
    __doPostBack('UpdatePanel1','')
}

This function is generated by the RegisterFunctionToPostBack() method.

// I decided to generate JavaScript Refresh() function, but you can
// write it by yourself and include in "LongPolling.js"
//
// Thanks to:
// http://geekswithblogs.net/mnf/articles/102574.aspx
// http://www.xefteri.com/articles/show.cfm?id=18 How postback works in ASP.NET
// and thanks to Dave Ward hint for calling __doPostBack("UpdatePanel1","") ,
public bool RegisterFunctionToPostBack(string sFunctionName, Control ctrl)
{ 
    // call the postback function with the right ID
    // __doPostBack('" + UniqueIDWithDollars(ctrl) + @"','');
    string js = "    function " + sFunctionName + @"()
            {
            " + ctrl.Page.ClientScript.GetPostBackEventReference(ctrl, "") + @"

            }";
    ctrl.Page.ClientScript.RegisterStartupScript(this.GetType(), sFunctionName, js, true);
    return true;
}

So instead of writing a parser for the Comet message in JavaScript and making DOM operations on the page, we just trigger the ASP.NET engine for a partial refresh of the page.

Query Notification

In this part of the article, I will try to show how to trigger Comet events using a Query Notification from SQL Server.

SqlDependency Class

To receive "Query Notifications", we can use the SqlDependency class. In the MSDN documentation of SqlDependency, you can read that you need to associate a SqlDependency object to the SqlCommand object and subscribe to the OnChange event. Then you must guess, that after these steps, you must execute this command. When executing the command, you will get some data. The OnChange event is raised when data from the command changes.

Table

In our case, we are interested in new rows from the table TestTable. Obviously, notifications can be received about any kind of update.

CREATE TABLE [dbo].[TestTable](
    [RecId] [int] IDENTITY(1,1) NOT NULL,
    [Text] [nvarchar](400) NULL,
    [Time] [datetime] NOT NULL CONSTRAINT [DF_TestTable_Time]  DEFAULT (getdate()),

    CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED ( [RecId] ASC )
        WITH (
            PAD_INDEX  = OFF,
            STATISTICS_NORECOMPUTE  = OFF,
            IGNORE_DUP_KEY = OFF,
            ALLOW_ROW_LOCKS  = ON,
            ALLOW_PAGE_LOCKS  = ON)
        ON [PRIMARY]
) ON [PRIMARY]

We can insert data in this table using a simple INSERT.

INSERT INTO TestTable (Text)
VALUES(N'Hello World!')

Step 1 - Check if we need to wait for changes

When the ASP.NET server is asked by the browser for notification about new data, the ASP.NET server checks if there is new data. If so, the browser will receive notification about new data without using a "Query Notification".

In our case, we are watching only insertions, so the query is very simple. We just check MAX(RecId).

// Query for making decision whether data was changed or we must wait.
// In our case we are interested in new records so we select MAX.
private const string queryForCheck = @"
SELECT MAX(RecId)
FROM dbo.TestTable";

// . . .

// 1. First query, to check if we need to wait for changes
using (SqlCommand cmd = new SqlCommand(queryForCheck, conn))
{
    int max = Convert.ToInt32(cmd.ExecuteScalar());
    if (max > lastRecId) // if max > last seen recId
        return false; // No async! New data available right now!
}

Step 2 - Run dependency

When there is no new data, we create and setup a new SqlDependency, associate it with a SqlCommand, and execute the command.

// This query follows rules of creating query for "Query Notification"
// and is filtered by record ID, because (in this case) we expect only
// "INSERT" of new records. We are not observing old records. To be
// compatible with Query Notification we must use schema name ("dbo"

// in our case) before table! For other compatibility issues you must
// search MSDN for "Creating a Query for Notification" or go to
// http://msdn.microsoft.com/en-us/library/ms181122.aspx
// And don't look at this: (old and incomplete list):
// "Special Considerations When Using Query Notifications" at
// http://msdn.microsoft.com/en-us/library/aewzkxxh%28VS.80%29.aspx
private const string queryForNotification = @"
SELECT RecId
FROM dbo.TestTable
WHERE RecID > @recId";

// . . .

// 2. Second query, to run dependency
SqlDataReader reader;
using (SqlCommand qnCmd = new SqlCommand(queryForNotification, conn))
{
    qnCmd.Parameters.AddWithValue("@recId", lastRecId);

    // Setup dependency which will be used to wait for changes
    depend = new SqlDependency(qnCmd);
    depend.OnChange += Depend_OnChangeAsync; // calback 1

    // Execute second query to run dependency (Query Notif.),
    // and to get content of our table data, that will be used
    // by Query Notification as a starting point for observing
    // changes.
    reader = qnCmd.ExecuteReader();
}

Step 3 - Handle rare cases

When executing a command to receive notification, it can be too late. Just before execution, data can be changed (inserted in our case) and we will not receive a notification. To prevent inserting new data between "Step 1" and "Step 2", you can put them in a transaction. This will block insertion of new data. I prefer to avoid blocking table in transaction in this case, because we can simply check if new data was inserted between those two steps.

// 3. Make sure that nothing has changed between point 1. and point 2.
//    (just before firing query notification)
bool newData = reader.HasRows;
reader.Close();
if (newData)
{
    // very rare case - data changed before
    // firing Query Notif. (SqlDependency)
    // TODO: test this case by making some Sleep() between 1. and 2.

    // We have new data and we decide not to receive notification:
    depend.OnChange -= Depend_OnChangeAsync;
    depend = null;

    return false; // No async! New data available right now!
}

Receive notification

When there is no new data, we successfully register to "Query Notification". When somebody or something inserts data to TestTable, then our Depend_OnChangeAsync() will be called. This method will call our ProcessAllWaitingClients() (discussed previously) which will deliver notification to clients.

Results

Precise time measurement is not important here. The most important thing is that time is not related to the polling interval, because there is no polling interval (as in a constant polling solution). If you buy a faster server, you will be faster. But let's make a time measurement just for fun.

Click here or here to enlarge. Press Esc key to stop GIF animation. 

Time measurement is started using a SQL INSERT (DEFAULT (getdate()) with an accuracy of 3.33 milliseconds). After that, a query notification is fired, and ASP.NET is notified. Then, a Comet notification is sent to the browser. The browser makes a refresh call. The server receives the refresh call. On the server side, time is measured again. This time, DateTime.Now (with an accuracy of 15 milliseconds) is used to measure time. The time measured is usually from 15 to 60 milliseconds on localhost (Intel Core 2 Duo 2.13GHz, 3 GB RAM).

Long Polling Implementation of Comet - Time Measurement

Why did I do the measurement on localhost? Because I'm not interested in the network speed, I am only interested in the speed of my code. If you wish to calculate the speed on your network, add some "ping" or "pong" speed to each arrow from the diagram.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

CoperNick
Software Developer
Poland Poland
Member
I graduated from the Jagiellonian University (and yes — I'm proud of this — and it was sometimes hard for me). After defence of master thesis (link to presentation) I have started professional programming in C and C++ using OpenGL. After that, my Company gave me a chance to switch to .Net framework and C# and I have betrayed my passion for computer graphics. Now I'm pure and happy C#, SQL and sometimes ASP.NET programmer.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionImplementing the same without using web pagesmembernicksaily27 Mar '13 - 0:34 
Hi,
 
I would like to know, how to implementing the same without using web pages like (html, aspx, php etc) and a request from a tool like REST Client.
 
Problem requirement I need to achieve is from messagedal file when there is no new records, the server has to wait for the changes and and returns the result. But in my case it is not happening and it immediately return if no record changes.
 
Please give a solution or guidance to achieve my requirements.
 
Thanks in advance...
Generalnice workmemberprem parihar2 Feb '13 - 4:56 
nice work. I really need it. thanx
GeneralMy vote of 5memberMd. Humayun Rashed30 Nov '12 - 3:27 
excellent
SuggestionNicememberVitaly Obukhov30 Nov '12 - 0:15 
I had the similar implementation of this solution.
One day client have asked me to develop dashboard page by which customers could track their requests within short delays.
We have discarded solution with classical request polling at once.
 
I have decided to implement my own long-polling solution since I didn't knew about sql server notifications feature yet or similar frameworks. Also we were running short of time Smile | :)
Basically we had asp.net mvc 3 & sql server 2005 on win 2003 R2 server and jquery for client side. So the workflow was following:
1. Customer opens page which contains client side long-polling logic implementation via jquery ajax & timers.
2. JS script sends request to separated mvc controller which has session state marked as "read only" to disable locking of another customer's requests.
3. Controller's action finds customer session in container and locks workflow via manualreseteventslim.
4. 3rd party app (from another server) modifies special table's data on sql server.
5. CLR trigger on this table calls another one controller.
6. This controller's action lookups session container using id data from trigger and unblocks workflow via manualreseteventslim.
7. First controller's action checks reason of unlocking (timeout or data modification) and responses to client with related data (if exists).
8. Finally client side JS script checks response reason code, handles data in related way and sends request to first controller again.
 
Well, there were a lot of tricky places in details but this worked just fine Smile | :)
After this I have read about SignalR Laugh | :laugh:
GeneralMy 5memberEpavesi27 Nov '12 - 23:38 
My 5
GeneralMy vote of 5memberEdo Tzumer27 Nov '12 - 19:10 
Splendid CoperNick,
In fact, it's the general idea for raising an event on the client's side, in a client-server environment
Questionproblem with online requestmemberRoukaya Allouche7 Nov '12 - 21:16 
hello all ,
thanks for this helpful example ,
 
I've been used it ..
it works fine on localhost, but when i put it online , the request doesn't fire after the connection is closed first time ,
in the other hand meaning, comet reverse ajax works just within first 1 min (waitTime) then the request is disconnected and doesn't reconnect again ,
GeneralMy vote of 5memberVarun Sareen20 Sep '12 - 21:50 
Awesome concept of refreshing the page with new data. A great and very good concept.
QuestionReally Good....membervkrh10 Aug '12 - 0:48 
Really smart work and good article...
 
Few of the people might get problem in using this for them they should run following commands
http://www.codeproject.com/Articles/12918/Using-Query-Notifications-in-NET-2-0-to-handle-ad
 
EXEC sp_configure 'show advanced options' , '1'; go reconfigure; go EXEC sp_configure 'clr enabled' , '1'
go
reconfigure;
go
 
ALTER DATABASE databasename SET ENABLE_BROKER
 
GRANT SUBSCRIBE QUERY NOTIFICATIONS TO username

QuestionBeginProcessRequest not firedmemberRajaSoorya15 Jun '12 - 5:20 
Hi,
I tried an almost identical application based on you article. I dont see the BeginProcessRequest being triggered. I read that BeginProcessRequest will not be triggered if the AsyncCallBack param to it is null. Please advise.
 
Thanks in advance,
Soorya
AnswerRe: BeginProcessRequest not firedmemberCoperNick19 Jun '12 - 11:29 
I don't know... Is the class derived from IHttpAsyncHandler? Did you try to invoke ASHX from browser?
 
Maybe you read this: "callback - The method to call when the asynchronous method call is complete. If callback is null, the delegate is not called." But this is not the same that you wrote. In this case callback is called delegate. So this is not the reason that BeginProcessRequest is not called.
GeneralRe: BeginProcessRequest not firedmemberRajaSoorya20 Jun '12 - 5:18 
There was a typo in the ashx markup. My bad.
The application works smooth. I am thinking of enhancing the application now to update/highlight only the values that have changed.
GeneralAwesome articlememberRajaSoorya7 Jun '12 - 10:45 
This article helped me understand comet programming and using SQLDependency with it.
Cant wait to try this out Thumbs Up | :thumbsup:
QuestionError 1 Could not load type 'HttpPushFromMsSql._Default'. C:\Users\amresh\Desktop\CometSql\HttpPushFromMsSql\Default.aspx 1memberMember 80026895 Apr '12 - 18:33 
I get this error when try to build.
AnswerRe: Error 1 Could not load type 'HttpPushFromMsSql._Default'. C:\Users\amresh\Desktop\CometSql\HttpPushFromMsSql\Default.aspx 1 [modified]memberM[r].George5 Jun '12 - 7:14 
I also have the same error "Could not load type 'HttpPushFromMsSql._Default' "
 
This code does not work. Maybe someone can edit or enter into to working code

modified 6 Jun '12 - 10:50.

GeneralRe: Error 1 Could not load type 'HttpPushFromMsSql._Default'. C:\Users\amresh\Desktop\CometSql\HttpPushFromMsSql\Default.aspx 1 [modified]memberCoperNick5 Jun '12 - 11:57 
Strange... I didn't change the zip with codes. Unfortunately I cannot check this today...
How your file Default.aspx.cs looks like?
It should look like this:
...
namespace HttpPushFromMsSql
{
    public partial class _Default : Page
...
 
What about designer.cs code? Is there any class _Default code? I'm asking because designer.cs code is regenerated when you touch aspx file.

modified 5 Jun '12 - 18:15.

GeneralRe: Error 1 Could not load type 'HttpPushFromMsSql._Default'. C:\Users\amresh\Desktop\CometSql\HttpPushFromMsSql\Default.aspx 1memberNisserX2 Sep '12 - 16:16 
I got this message as well when I was loading the sample code into a website and trying to then open the website with Visual Studio 2010 as a "website". I had load the sample files into my website, then open it from the included project file, run it once (build) and then I was able to close it down and then I was able to run it as a "website" on my devlopment webserver without the error message
Questionauto update not working in subfoldersmemberMember 791214523 Jan '12 - 4:58 
This app seems to work great however whenever I put my filename.aspx file in a subfolder and call these scripts it only seems to display alerts on the page load and not automaticly. The
 
if (ScriptManager1.IsInAsyncPostBack) // AJAX partial update
{
      RefreshData();
}
 

seems to never get called. would anyone know how to fix this?I renamed all of my links to "~/scripts" so the path is correct. I also tried coping the scripts folder into the same folder but it doesnt seem to matter.
AnswerRe: auto update not working in subfoldersmemberMember 791214524 Jan '12 - 8:44 
it seems that this issue stems from the following line in longpolling.js/function longPolling()
 
$.ajax({
      type: "GET",
      url: "CometAsyncHandler.ashx?waitTime=60", // one minute
 
it seems that it can not find this file since I'm calling it from the main folder and a subfolder.Which would explain the issue However whenever I add change it to:
 
$.ajax({
       type: "GET",
       url: "../CometAsyncHandler.ashx?waitTime=60", // one minute
 
then it will work fine when I am debugging on my local machine in Visual Studio 2010. However once I deploy it to my webserver it doesnt find the file so nothing works. So I tried using the relative path char
 
$.ajax({
    type: "GET",
    url: "~/CometAsyncHandler.ashx?waitTime=60", // one minute
 
but it doesnt work in my debugger or on the live site.
 
Would anyone have any suggestions on how to get this to work in a multi-folder environment?
 
Thanks
QuestionPage data refreshing after getting some stroke/signal from server that there is some changes on database tablememberMember 37789463 Jan '12 - 16:28 
I am trying to do something same in my Final Semester Masters Work on AJAX, but not able to do this. Can you please help me.I am giving you details of my work.......and problems i m facing....and need your help..........
 
I made 2 pages.
Page 1 is the registration page from which a student can update his/her information.
Page 2 is the index page(works as home page) which shows the number of students who updated their information.
 
At present i made 3 versions of page 2, Named as Index1, Index2, Index3.
 
Index1 shows the number of students using Classic web page (Complete Page reloading).
 
Index2 shows the number of students using Ajax enabled Web page (Page reloading after some predefined time interval for updated information) with number of bytes downloaded.
 
Index3 shows the number of students using Ajax enabled Web page (Page data refreshing after getting some stroke/signal from server that there is some changes on database table.)
 
Note:
The number of students will change, when a student submit his/her information through a web page(UpdateInfo.aspx)
 
My Problem is-->
Not able to implement my logic in Index3
 
Please help me.
AnswerRe: Page data refreshing after getting some stroke/signal from server that there is some changes on database tablememberCoperNick6 Jan '12 - 1:03 
Hello
 
My solution is the explanation of how to implement your "index3" by combining Comet functionality and Query Notification functionality. My solution do not work in SQL Server Express.
In your case you can implement only Comet functionality without using Query Notification, because all changes to SQL Server are done only by your application. Instead of waiting for changes from SQL Server you must wait for user action that that is changing data in server. So you fire Comet notification just after you update data in SQL Server. Instead of waiting for Query Notification that will call CometAsyncHandler.ProcessAllWaitingClients() you should call it when you update data in server.
 
I hope that it helps you.
QuestionDoesn't this require a LICENSED version of SQLServer?memberBill SerGio, The Infomercial King9 Dec '11 - 13:18 
Hi,
 
Doesn't your project require a licensed version of SQLSErver?
 
The FREE version SQLServer doesn't allow you to create an endpoint?
 
Bill SerGio
http://www.GeminiGroupTV.com

AnswerRe: Doesn't this require a LICENSED version of SQLServer?memberCoperNick6 Jan '12 - 0:22 
Every version have licence. "Express" version is free but it doesn't have "Query notification". You must use trial version or "Developer Edition". So in general, to use this solution you or your client must pay for SQL Server.
GeneralMy problemmemberMember 374668110 Feb '11 - 17:12 
I have problems while creating one or more other support for Comet.
 
Please give solution!
 
Thanks,
bitctu

GeneralGreat article!memberMember 37466819 Feb '11 - 15:31 
I am understanding Comet. Your article is very useful!
 
Thanks CoperNick!Thumbs Up | :thumbsup:
bitctu

GeneralMy vote of 5membermark_e_bond27 Dec '10 - 8:38 
Besides being the only working server side example I could find, it introduced me to SQL notifications which solved a problem I didn't even know I had.
Thanks for taking the time to post your example.
QuestionVB version of source code?memberb16b1819 Jul '10 - 19:59 
I'm having trouble converting some of your code to VB. Specifically,
 
AllWaitingClients.RemoveAll(
delegate(CometAsyncResult asyncResult)
{
if (asyncResult.StartTime.Add(asyncResult.WaitTime) < now)
{
asyncResult.Result = false; // timeout
asyncResult.Callback(asyncResult);
return true; // true for remove from list
}
 
return false; // not remove (because not timed out)
});
AnswerRe: VB version of source code?memberAleksandr Vaysberg1 Nov '12 - 7:22 
Hi, have you been able to convert it into VB.NET?
 
Thanks.
GeneralNot working on web servermemberb16b1814 Jul '10 - 20:53 
Hello, I have your sample project working great on my local pc but when I tried to deploy the solution to my hosting service I just get the contents of TestTable displayed on page load with this error (undefined). Not sure what to check to resolve this. Any suggestions? Thanks
 
Item
hello (Time of data: 11:36:04.043 PM)
hello (Time of data: 11:48:38.497 PM)
hello (Time of data: 11:48:45.567 PM)
helloooo (Time of data: 11:48:54.703 PM)
error (undefined)
Connect again
AnswerRe: Not working on web servermemberCoperNick15 Jul '10 - 7:54 
Hello, I looks like server side responds with some http error on ajax request. Try to extend error handling on jQuery ajax request. Currently it is to simple:
error: function(XMLHttpRequest, textStatus, errorThrown){
    isPolling--;
    addLongPollingError("error", textStatus + " (" + errorThrown + ")");
}
 
Try to find something interesting in first parameter - XMLHttpRequest. I'm not an expert on JavaScript, try to google for proper error handling on ajax request. I think that this can be good starting point: http://stackoverflow.com/questions/377644/jquery-ajax-error-handling-show-custom-exception-messages[^]
GeneralRe: Not working on web servermembersmalltom1 Dec '10 - 16:27 
I have the same error, does anyone have a way to workaround Smile | :) ?
GeneralRe: Not working on web servermember1nfinity6 Dec '10 - 5:40 
I also have the same error. In debug mode I found that Service Broker was desabled.
I solved the problem as follows: ALTER DATABASE [Database Name] SET ENABLE_BROKER;
GeneralSqlDependency is not in mysql What to do plz helpmembershaikhsamir21 Jun '10 - 19:50 
Hello guys,,
 
This is great article.
But what to for mysql because it hasn't
sqldependency...
 
thanxxx,
samir
GeneralRe: SqlDependency is not in mysql What to do plz helpmemberCoperNick23 Jun '10 - 4:36 
Hello Samir,
 
Thanks. One of the requirement is to have Microsoft SQL Server (and not Express edition). Microsoft Query Notification is implemented by Microsoft on Microsoft SQL Server. It will not work in MySql. You can leave Comet functionality as it is, but instead of SqlDependency you can implement some constant pooling to MySql. If you discover some changes in database you can fire comet notification. This solution will give you one thread that pooling database (instead of 100 for example in case where each browser is pooling), but will not give you such speed. But if your query is simple and fast your pooling interval can be very small so it is still possible to be very fast.
 
I'm not an expert of creating background work in ASP.NET (data pooling to MySql in this case). Maybe simple "new Thread()" can be created to do the job. ("Job" means waiting for new data by constant pooling).
 
CoperNick
GeneralI have done the same thing 1 years agomemberreborn_zhang6 Mar '10 - 1:34 
I use XML protocol. and build the comet channel as the "LIVE-CHANNEL", so I can search any database, by http protocol.
 
but.. the comet channel is not stable, so I plan to build due-comet channel, to reduce the comet tranfer delay, and increase the stability.
QuestionHow do you manage with multiple (mass) insert on SQL Server?memberMember 4558665 Mar '10 - 22:03 
Hi!
Nice article!
How do you manage (Comet) with multiple (mass) insert on SQL Server in practice?
Rand
Rand
modified on Saturday, March 6, 2010 4:16 AM

AnswerRe: How do you manage with multiple (mass) insert on SQL Server?memberCoperNick6 Mar '10 - 4:32 
Thanks!
 
Query Notification event is send only for first INSERT (or other updating command) after registration for receiving. When browser receive notification then Refrash is called, when refresh is called SQL Server usually have all data updated/inserted so browser will get all inserted data. When “multiple” (for example 1000) INSERTs is still working, then browser will get only some part of new data (for example 600). After that browser will register for Comet messages again. In “Step 1” (see in article) ASP.NET will discover that there is already new data inserted (for example 400 rows) so browser will receive response immediately that there are new data. Browser will call Refresh() again and will get rest of data.
 
This solution is for getting data fast, rather than getting very frequent. If something will make “mass” insert (100 rows) once for an hour or once for a minute, or even once for 5 second it will work, but if data (even small) is inserted very frequently (for example one row for 50ms) browser will get Comet event very frequent - this can kill your network. In this case some Sleep should be introduced when this situation will be discovered. If regular, constant and very frequent INSERT is a normal situation, then you should not use my solution. In this case You will prefer constant polling probably.
 
If frequent INSERT happens only from time to time, and You want get notification when it is started, you can make a little change to code to get some mixed mode implementation (long polling mixed with constant polling)
 
function EndRequestHandler(sender, args)
{   
    if(isPolling == 0)  // this "if" prevents from runing two requests
    {
        // make some seep here to implement "mixed mode"
        // this sleep will prevent from calling refresh to fast
        // Sleep(5000)
        longPolling();
    }
}

GeneralRe: How do you manage with multiple (mass) insert on SQL Server?memberMember 4558666 Mar '10 - 9:50 
Thanks
RAnd
Rand

GeneralRe: How do you manage with multiple (mass) insert on SQL Server?memberBassam Saoud10 Mar '10 - 6:40 
Why was your post 1 voted?
GeneralRe: How do you manage with multiple (mass) insert on SQL Server?memberCoperNick14 Mar '10 - 10:23 
Bassam Saoud wrote:
Why was your post 1 voted?

 
I don't know. But message with “Thanks” was also voted, so I believe it was for fun. Big Grin | :-D

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 27 Nov 2012
Article Copyright 2010 by CoperNick
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid