Microsoft Gold Certified Partner

Archive for the ‘Uncategorized’ Category

Asynchronous ASP.NET MVC and SqlDependency

Tuesday, July 12th, 2011

This is a quick example showing how to set up Asynchronous Actions in ASP.NET MVC and SQLDependency using a standard example – Chat application.

1. IIS Threading

IIS 7 creates a new thread from the thread pool whenever it receives a request from the client. When the thread processes the request synchronously it cannot handle other requests since it’s waiting for operation completion. This can be a problem for applications with a big number of requests and long running IO operations. (this is a very simplified version, lots more is happening in IIS but let’s not worry about this…).
When the thread pool no longer has any available threads on the server the requests will start being queued in the global IIS queue. Once the queue reaches its limit IIS will start returning “Server Busy” AKA 503.

503 error

This error is often generated when we are performing long running synchronous tasks or spamming the server with requests when it’s not really needed. A good / classic example of an application that can do both is the chat application.

When created incorrectly you can use JavaScript setInterval/setTimeout to get data from the server every X ms/s regardless of the changes (pooling).This will cause a big load on the server for every client / browser tab open.

There are several solutions for this problem. One of them is to use a long pooling technique:

2. Asynchronous request to the rescue

When an asynchronous request is executed on the CLR Thread Pool instead of waiting  for the process to finish, the thread can go back to the thread pool and serve other request. Once the processing is finished a new thread (or the same…) is dispatched to process the remainder of the request and render the results. This increases performance for long running operations since threads can be used in a more efficient way.

I’ll use SqlDependency to get notifications whenever someone submits a chat message and asynchronous MVC actions to keep requests open and update the Chat window only when needed.

3. SqlDependency configuration

SqlDependency allows registering for query notifications in SQL server. This allows us to be notified on the changes in the thunderlying database instead of querying it for changes.

  • Enable CLR integration

EXEC sp_configure 'clr enabled', 1

go

RECONFIGURE
  • Enable SQL Service Broker

ALTER DATABASE <DataBaseNameHere> SET ENABLE_BROKER
  • Setup user permissions

GRANT CREATE PROCEDURE TO <UserNameHere>;

GRANT CREATE SERVICE TO <UserNameHere>;

GRANT CREATE QUEUE TO <UserNameHere>;

GRANT REFERENCES ON CONTRACT::[http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification] TO <UserNameHere>;

GRANT SUBSCRIBE QUERY NOTIFICATIONS TO <UserNameHere>;

GRANT CONTROL ON SCHEMA::[dbo] TO <UserNameHere>;

GRANT IMPERSONATE ON USER::DBO TO <UserNameHere>;

4. “Coding” SqlDependency

Implementing SqlDependency is fairly simple but has a few quirks. To get the SqlDependency working you just need to:

  • Call SqlDependency.Start method which will start listening for notifications.
  • Create and Open new SqlConnection
  • Create SQL command that you want to “listen to”. In my example I’m listening for changes in all chat messages in a room specified by constant “ROOM_NUMBER”.
  • Create new SqlDependency object that takes SqlCommand as a parameter and handle OnChange event. This event will fire whenever there is a change that affects the results of our query.
  • Execute Query

Unfortunately LINQ to SQL or Entity Framework does not work with SqlDepenency. That means there is no way to create a new EF ObjectContext, create a LINQ query and use it as SQL notification subscription. There is no way…or I just didn’t find a way, that is. If anyone knows how to do it please let me know! (I’ve tried


System.Runtime.Remoting.Messaging.CallContext.SetData("MS.SqlDependency", dependency.Id);

but couldn’t make it work…)

Keep in mind that when working with SqlDependency:

5. Simple chat application

To create Asynchronous actions in MVC we need to:

  • Make the controller inherit from AsyncController
  • Action method needs to be divided into 2 methods:

<MethodName>Async ( this method needs to return void ),

<MethodName>Completed (this method returns actual ActionResult )

  • AsyncManager contains several properties/methods that are required to create asynchronous action:
    • Increment / Decrement – these 2 methods exposed by OutstandingOperations property are used to indicate the start and end of long running tasks to AsyncManager.
    • Parameters dictionary is used to store results of running tasks. Every key from this dictionary will be passed as parameter to <MethodName>Completed action.

There are also 2 interesting attributes that will help us in creating Async actions:

       AsyncTimeout

and

       NoAsyncTimeout

Names of these Action Filter attributes should be self-explanatory. By default async method will time-out after 45 seconds. In that case we can either write the code to re-request an asynchronous method or set it disable timeout. In this example I’ll go with setting timeout to 90 seconds so we can see what’s actually happens.

Sample code controller code (I hope that the code comments and the explanation above should make this clear):


public class ChatController : AsyncController {

      [AsyncTimeout(90000)]
      public void GetMessagesAsync(){
             AsyncManager.OutstandingOperations.Increment();
             SqlConnection conn = null;
             try
             {
                  string connString = ConfigurationManager.ConnectionStrings["ChatConnectionString"].ConnectionString;
                  conn = new SqlConnection(connString);
                  conn.Open();    // open new connection and create command to notify about all new Chat-Messages in -ROOM_NUMBER- const
                  using (var sqlCommand = new SqlCommand(@"SELECT dbo.Chat.Id FROM dbo.Chat WHERE dbo.Chat.RoomNumber = @room", conn))
                  {
                        sqlCommand.Parameters.AddWithValue("room", Configuration.ROOM_NUMBER);
                        var sqlDependency = new SqlDependency(sqlCommand);
                        //handle onChange event - this will be fired whenever there is a change in database that affacts our query
                        sqlDependency.OnChange += (sender, e) =>
                        {
                            //change detected - get all messages...
                            Models.MyValetBayEntities entities = null;
                            try
                            {
                                  entities = new Models.MyValetBayEntities();
                                  var query = from c in entities.ChatRoom
                                  where c.RoomNumber == Configuration.ROOM_NUMBER
                                  select c;
                                  AsyncManager.Parameters["chatModel"] = query.ToArray();
                            }
                            finally
                            {
                                  entities.Dispose();
                                  //...and complete async operation
                                  AsyncManager.OutstandingOperations.Decrement();
                            }
                        };
                   //execute query with associated SqlDependency to subscribe for notifications
                   sqlCommand.ExecuteNonQuery();
                 }
           }
           catch {
               //make sure that if something goes wrong we are still have proper AsyncManager operations count
               AsyncManager.OutstandingOperations.Decrement();
           }
           finally
           {
               if (conn != null)
               {
                   conn.Dispose();
               }
           }
       }
       public ActionResult GetMessagesCompleted(Models.Chat[] chatModel){

              return PartialView("Chat", chatModel);
       }
}

Sample Javascript:


$.ajaxSetup({
      // Disable caching of AJAX responses
      cache: false
});

function getNews(){
         $.ajax({
           url: '@Url.Action("GetMessages", "Chat")',
           success: function (data) {
                    //update messages ...
                    $('div#content').html(data);
                    //... and subscribe for notification again
                    getNews();
           },
           error: function () {
                  getNews(); //timeout error create new request
           }
         });
}

getNews();

Part of Global.asax

protected void Application_Start(){
      //... MVC registration removed for simplicity
      SqlDependency.Start(connString);
}

private void Application_End(){
      SqlDependency.Stop(connString);
}

DEMO (off-line)

An asynchronous request waiting for information from the server in action:

IE Pending

Chrome Pending

6. The End…

I hope you enjoyed my post. This demo could be probably improved by using HTML5 WebSockets but that’s something for another blog post since WebSockets are not supported that well yet…

Please also note that creating asynchronous methods will be simplified with C# 5 with async and await keyword. Have a look at http://msdn.microsoft.com/en-us/vstudio/gg316360 for more details but please be careful with installing it since it’s only CTP (at the time of writing this blog post).

Mud Glorious Mud! The FelineSoft development team get plastered…

Wednesday, November 17th, 2010

Date: 12th November 2011
Venue: Max Events, Bristol
Weather: Wet and windy

Finally, the day set aside for the FelineSoft dev team to have some fun arrived along with a rather rainy and blustery spot of weather. After donning overalls and posing for a pre-mud bath photo shoot, the Bristol dev team looked more like a bunch of factory workers than the usual motley, slightly geeky crew of .Net developers.

First up was the quad biking circuit and the team were soon getting stuck in (not literally -yet) and ripping round the course. Pete, our Tech Director, with his childhood ’scrapheap challenge’ background was most definitely the fastest rider- at least one of us was lapped by him several times in one sitting!

Check out the video here
and the photos here

Next up was the ‘off-road rage buggies’ and what can only be described as the muddiest thing I’ve ever done apart from getting into a hot mud bath in southern Japan. Unfortunately the mud wasn’t even warm, but at least there weren’t any old men gawping at me this time…

The challenge of driving the Mad Max style buggies was being able to get enough mud off your goggles to actually see where you were going at the same time as trying to grip onto the slippery steering wheel – amazingly noone managed to crash or go upside down but we all managed to get completely plastered in mud from head to toe.

The third activity was ‘hovercrafting’, an unbelievably frustrating way of getting around on dry land if you ask me! One of our SharePoint guys, Paul, managed to cruise around the course without getting stuck and scored 9 out of 10 – you don’t know how good that is unless you’ve tried it yourself! The rest of us spent most of our time getting stuck in the long grass and waiting like helpless children to be rescued by the Max Events instructor.

After a very welcome late lunch, we headed off for the final activity of the day- crossbows. Our project manager Jason with his military background gave us some top tips on how to aim for the kill, but it was Pete our Tech Director who actually scored the highest in the final target practice. Lucas, one of our genius .Net developers, and Paul were close seconds though.

By the end of the day, we were a bit cold, wet and utterly plastered in mud and quite happy to get onto our return minibus (notably not the same plush one that delivered us there that morning LOL). Conversation on the bus turned to the usual random topics we have here at FelineSoft- did you know that Johnny Cash was nearly killed by his pet emu? And did you also know that duck-billed platypuses have a poisonous stinger on their feet either did you?