Sunday, September 30, 2012

Queue up jQuery requests before it is loaded

If you are loading jQuery just before the closing body tag (if not, stop and read this now), you may be wondering how you can use jQuery before it has been loaded on your page above. Maybe it forced you find some crazy script ordering scheme or maybe you just gave up and included it somewhere else in the body or even in the head.

In a CMS world, each widgets could emit javascript that relies on jQuery existing on the page, but since it isn't loaded until just before the closing body tag, we need a way to fake a reference to jQuery and queue up the requests temporarily until jQuery has been loaded.

I came across this post that seemed to do exactly what we needed. Before jQuery is loaded, the script will queue the jQuery functions calls. Once loaded, the functions are dequeued and executed. Hooking up the script is simple and only involves adding a few small scripts to your page. 

First you have to add an inline script to your head tag. The script will create a fake $ reference on the window if jQuery hasn't yet loaded which pushes each function onto an array. It then defines a new function that will be used to execute each function after jQuery eventually loads.

<script type="text/javascript">
(function (a) {
 if (a.$ || a.jQuery) return;
 var b = [];
 a.$ = function (c) { b.push(c) };
 a.defer$ = function () { while (f = b.shift()) $(f) } }

Next include jQuery just before the closing body tag.
<script type="text/javascript" src="/scripts/jquery.min.js">

Finally, after the jQuery include, call the defer function that we defined in the header. This will loop through each function that was deferred and execute them now that jQuery has been loaded.

<script type="text/javascript">

This is a pretty cool trick, and while I can't take credit for it, I wanted to put the information out there for others to learn from.


Thursday, June 14, 2012

Working around RavenDB and Safe-By-Default

I have seen these questions from time to time.
"How can I get all of the documents in RavenDB?"
"How can I force RavenDB to return more documents that the "safe-by-default" limits?"
The questions above usually stem from someone needing to work around the "safe-by-default" protection due to some sort of special circumstance. So if you find yourself needing these techniques more often than not, then you are doing it wrong.

You can change the RavenDB configuration by increasing the default PageSize, but that is a global change. Instead you need to do two things.
  1. Ensure that you start a new DocumentSession when you reach the  MaxNumberOfRequestsPerSession limit.
  2. Make sure you page the query with respect to the RavenDB PageSize (which is 1024 by default).
The RavenDB paging mechanism will not override the configured maximum number of items allowed per page. So if you try to Take() more than the configured limit, you will not get an error. Instead RavenDB's safe-by-default kicks in and will impose the configured page size on your results.

Below is an example that gets all document id values that match the predicate.

IDocumentSession session = null;
    session = MvcApplication.DocumentStore.OpenSession();

    List<string> ravenPageIds = null;
    const int RAVEN_MAX_PAGE_SIZE = 1024;
    int currentPageNumber = 0;

        List<string> tempRavenPageIds  = (from p in session.Query<Page>()
                                          where p.IsActive == true
                                          select p.Id)
                                          .Skip(currentPageNumber++ * RAVEN_MAX_PAGE_SIZE)


        if (session.Advanced.NumberOfRequests >= session.Advanced.MaxNumberOfRequestsPerSession)
            session = MvcApplication.DocumentStore.OpenSession();
    } while (tempRavenPageIds.Count == RAVEN_MAX_PAGE_SIZE);

We had code similar to this that needed to run when an MVC Application started (in order to build page routing table). But since then, we were able to refactor the code such that we no longer need to employ this technique. Rather than simply throw it away, perhaps you may find it useful.


Thursday, May 24, 2012

MVC3 Razor and Preprocessor Directives Deficiency

You may have used preprocessor directives in ASP.NET Webforms to conditionally include code segments in markup for in the code-behind files. I have used them in master pages and aspx pages to do things like conditionally including Google Analytics or include compressed versus verbose CSS and Javascript.

Example including Google Analytics when DEBUG is not defined.
<% #if !DEBUG %>
<script type="text/javascript" src="/scripts/ga.min.js"></script>
<% #endif %>

Example including verbose CSS versus minified CSS.
<% #if DEBUG %>
<link rel="stylesheet" href="/Styles/Default.css" type="text/css" />
<% #else %>
<link rel="stylesheet" href="/Styles/Default.min.css" type="text/css" />
<% #endif %>

If you are like me, you may have tried to use this technique in MVC3 Razor. But what you may not know is that MVC Razor views are always compiled in DEBUG mode! That's right, it does not respect the debug attribute on your compilation web.config element! This is a huge issue, and frankly I am surprised that this has not yet been fixed.

In trying to find answers, I found this response on this thread which confirms the issue.

There is hope though! We have a few ways that we can conditionally include code in our Razor views.

Use IsDebuggingEnabled

Instead of using preprocessor directives in Razor, you can instead use the following property to test if the web.config compilation element's debug property (Reference here: Stack Overflow).

That property will check your compilation element's debug property in web.config.
<system.web><compilation debug="true">...</compilation></system.web>

Create a Static Extension Method that uses preprocessor directives

Shawn on Stack Overflow posted an example of an extension method that can be used in conjunction with preprocessor directives.
    public static bool IsDebug(this HtmlHelper htmlHelper)
      return true;
      return false;

Then in your view, just check IsDebug().

IMHO, this issue should be addressed in MVC4. There is no reason for the code bloat that Razor causes by not respecting the DEBUG compilation flag. If anyone can find the Microsoft connect issue, please comment and I'll add in my 2 cents!