AllPaul

programming, tech, hobbies and grief

30. March 2013 07:17
by Paul Apostolos
0 Comments

Set Session State to Read Only on AJAX-Called MVC Controllers

30. March 2013 07:17 by Paul Apostolos | 0 Comments

On a recent line-of-business browser-based application implementation I ran across a very interesting issue.  The application calls another back-end application through a specialized data provider to display customers, employees and invoices. Because this data doesn't change that often and the validity of the data isn't that important, I decided it was a perfect candidate for caching.  In addition to caching, I want to be sure not to block the current http request while the application fetches the data into the cache from the provider, so I planned to implement a JsonResult MVC controller to allow me to fetch the data in an asynchronous AJAX request. That all seemed pretty straight forward when I first thought about it.  However, in reality, it was a few months of wrestling with the caching story, trying different providers and even building a windows service to alleviate the long client requests.  In the end, I only needed to be better at Google/Bing and the whole thing could have been done in a day.

People still use QuickBooks?

This project was a employee time tracking/job costing/inventory management application for a construction company.  One of the big selling points of the new application to the account stakeholders was the integration with QuickBooks.  I reviewed a few QuickBooks data providers before the project began and it seemed fairly straight forward. The two main players in the QB data provider market are QODBC and RssBus. Neither of them are very fast or easy to implement.  In the end, I decided on RssBus because they offered an install-as-a-service remote connector (to allow my application to connect to QuickBooks even if QuickBooks isn't open on the server) and they offer an EntityFramework provider.

I installed and configured RssBus and built a model with just a few entities: employees, customers and invoices. Then I created the rest of the data access repository and added that library to my solution. At this point, I was thinking I would be done in another hour or so...

The MVC and JavaScript story

I added a new MVC controller to application and called it QuickBooksDataController (it turns out that this is the one thing I did correctly from the start) and made a few methods to get the collections and return them as Json.

QBRepo repo = new QBRepo();
public JsonResult GetEmployeeNameAndID()
{
   var employees = repo.QBEmployeeNamesAndIDs.Select(c => new { ID = c.Key, Name = c.Value });
   return Json(new { result = true, data = employees }, JsonRequestBehavior.AllowGet);
}

Then I created a JavaScript AJAX method to get the data on a page after the page was done loading.

$(document).ready(function () {
     var ddl = $('#ddlQBEmployeeID');
     ddl.prepend($('<option></option>').html('Loading...'));
     $.getJSON("/api/QuickBooksData/GetEmployeeNameAndID", null,
          function (ret) {
              var selectedItem = '@Model.QBEmployeeID';
               $('#ddlQBEmployeeID').empty();
               $.each(ret.data, function () {
               $('#ddlQBEmployeeID')
                     .append($("<option />").val(this.ID).text(this.Name));
                });
                if (selectedItem.length > 0) {
                    $('#ddlQBEmployeeID').val(selectedItem);
               }
        });
 });

At this point I thought I was pretty much done. So I right clicked on project and chose View in browser....The page did exactly what I thought it would...It loaded everything and while the QuickBooks data was being fetched, the select list displayed "Loading...".  After 70 seconds, the select list populated.  I thought, obviously, I need some caching.

Time for some caching

Well, RssBus provides built in caching so I tried that.  I just needed to change the connection string and the provider would cache automatically;so I did that. I then refreshed the page and still 70 seconds on the first request...Ha, on the second request it was just a few seconds though. Now, I thought I was done...like really done. But, I hadn't really uncovered the problem.

So, where's the problem?

During some other testing I noticed that if I clicked on a page that had one of these AJAX requests to a long-running process (like repo.QBEmployeeNamesAndIDs) that the next time I clicked on a page I would still need to wait the full 70 seconds before a different page (without any AJAX requests on it) would be served by the server. And, what's worse is, the normal path of entry to the application is home page (with a few of these requests on it) to login page. By that I mean, the user will go to the application home page and click on the login link (or another link that will force them to log in).  The process from home to login was taking 70+ seconds. 

To allieviate the problem I tried literally every different type of asynchronous programming method: Background Worker, Async/Await, TaskFactory, and even a separate windows service. Nothing was simple and it seemed no matter what I did I still had the delay issue.

So, what fixed it? 

I was up late pulling my hair out when it dawned on me...The issue I was experiencing was not related to the caching of the data.  The issue I had was, IIS was blocking all requests (per user, but I didn't know that until I figured out the whole problem) until a single request finished. That was a sanity check...Why would it do that?  So instead of Google/Binging for caching strategies and asynchronous request methods, I changed my query to "long running ajax request blocks MVC". That was it.  I was on my way to the answer.  After several StackOverflow questions and answers I found it and it makes total sense.

Session state blocks on each request per user just in case something is changed in the user's session from one request to another.  So, basically, my AJAX requests were blocking other requests in order to modify the user's session if required. But, I didn't need session state modification during these requests, so I needed to figure out how to turn it off.

Remember when I said I created a controller just for the QuickBooks data and that was one of the only things I did right? Well, because there was just one controller with these methods in it I simply needed to decorate the controller with a data annotation to signify that it wouldn't be modifying session state:

[SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)]
public class QuickBooksDataController : Controller
{
    QBCacheManager cm = new QBCacheManager();
    public JsonResult GetEmployeeNameAndID()
    {
        var employees = cm.QBEmployeeNamesAndIDs.Select(c => new { ID = c.Key, Name = c.Value });
        return Json(new { result = true, data = employees }, JsonRequestBehavior.AllowGet);
    }
}

Seriously, it was that easy. [SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)] is all I needed.

Wrapping up

So, I learned a lesson here...It's not supposed to be hard and if it is, I need to double and triple check that I am going down the right path. And, set session state to read only for AJAX request controller actions.

Good luck to you!

25. March 2013 05:36
by Paul Apostolos
0 Comments

AttachTo Visual Studio Extension

25. March 2013 05:36 by Paul Apostolos | 0 Comments

I spend around 80% of my day coding Web applications in Visual Studio 2012.  Typically, these applications are configured to run locally for testing using IIS Express and then (cross my fingers) are published to the server once all the bugs are ironed out.  This testing can be as simple as running the site and determining if everything looks right or as complicated as attaching to the IIS Express process and going through the code of the site step by step looking for a particular issue's cause. If you are anything like me, you do lots of viewing of the site you are developing...looking at every little CSS, HTML, route, action or JavaScript change.  In order to make my life a little easier, I use a relatively unknown Visual Studio extension called AttachTo.

AttachTo Installation

Seriously, this is one of my favorite Visual Studio extensions ever.  AttachTo allows me to attach to a running process of IIS Express, IIS, or NUnit with one click.  Previously, if I wanted to attach to a running process of IIS Express, I would have go to the TOOLS->Attach to process-> and then hunt for the process I wanted.  AttachTo makes it simple; click = attached.

To get AttachTo, go to TOOLS -> Extensions and Updates and search for "AttachTo" under the Online -> Visual Studio Gallery option.

Click the "Install" button (mine is already installed, so I have a green check mark where the install button would be), and that's it.  Well, sort of.  I also like to save clicks by moving the "Attach to IIS Express" menu item to the toolbar.  And that's totally easy too.

Adding AttachTo to the toolbar

To add the "Attach to IIS Express" menu item to the toolbar, go to TOOLS -> Customize. Then click on the Commands tab, choose the radio button for Toolbar and select Standard from the Toolbar dropdown menu.

Next click on the Add Command... button and under categories choose Tools. Then, from Commands, choose "cmdidWhutAttachToIISExpress".

From there I did two more things just to clean it up a bit.  I moved the item (using the Move Down button) to just before "Find in files".  Then I renamed it using the Modify Selection button. 

That was it.  Now anytime I want to attach to a running instance of IIS Express, I just click the little AttachTo icon on the toolbar and I'm all set.  No more hunting through a list of processes.  Time = saved.

Wrapping up

AttachTo saves me time every single day.  For more information about AttachTo, check out the details page in the Visual Studio Gallery or check out the project's repository on GitHub

Good luck to you!

28. February 2013 05:39
by Paul Apostolos
0 Comments

If you are not using Trello, you are doing it wrong

28. February 2013 05:39 by Paul Apostolos | 0 Comments

If I had a nickel for each todo or project management application I have tried...Well, let's just say, I'd have a crapload of nickels. Trello is the todo/task management application that is painfully easy and has just enough features to not be overwhelming but still be entirely useful.

Getting started with Trello

Trello makes it easy to get started by allowing you to either sign in with your Google account or sign up for a Trello account with only three required fields. From there you confirm your account with via a link sent to your email address and you are ready to start Trello(ing).

Creating your first Trello board

Trello uses the concept of a board (like a virtual bulletin board) as the home for any project (or task list). To create your first board, go to your Trello home screen where you should see a link to create a new board. Alternately, there is a "Boards" link in the top right corner that, when clicked, reveals a list of all your boards and from there you can choose the "New Board..." link.

The newly created board has three lists by default: To Do, Doing and Done.  A list is just a logical grouping of cards (tasks or whatever) and you are free to create, rename or delete any lists. 

The next step is to start adding items (Trello calls these cards) to the lists. In my example I am creating a website for a fictional ABC company (I probably should have gone all Wile E. Coyote and chosen Acme). I have added cards to the To Do list representing the tasks required to fulfill this project. 

As the tasks are in process I can move the to the Doing list and from there finally to the Done list.  But these lists could be defined in any way. For example, for this website, I could have created lists for: Planning, Design, Prototype, Coding, Testing and Go Live.

Lists and cards are meant to be flexible so flex them into your own personal style or workflow.

Sharing your Trello board

One of the coolest features of Trello boards is the ability to share them with other team members, family, friends or zombies. The only prerequsite is that the user have a Trello account. 

To add members to a Trello board, on the right side choose "Add members..." and just type the name (or email address) of the user you would like to add.

 

The user will receive an invitation to join the Trello board and that's it -> the collaboration magic will happen.

Accessing Trello from any device

Another thing that's great about Trello is it is accessible from (almost) any device. Trello should work in the browser of any recent smartphone or tablet.  And, Trello has Apps for Android, iOS and Windows Phone. I am using the iOS app and it just works.

Wrapping up

This post only scratches the surface of the features of Trello. Trello simple and useful for keeping track of projects and collaborating on task lists with teams, family members or friends.  So, whether you are planning a party for your daughter's sixteenth birthday and you don't want to let anything slip through the cracks, or building a website and need to collaborate with team members, Trello is a great choice. Form more information about Trello, visit the Trello site, or watch this video: 

Give it a try and let me know what you think.

Good luck to you!