Alexander Beletsky's Development Blog: 2012-04

CS101 Building a Search Engine: Week 2

Disclaimer: this blog post expresses some impressions and details of Udacity CS101 "Building a Search Engine" online course. If you are either currently participating it or plan to do so in nearest future, this blog post could be a spoiler. Even though, I'm trying to make it generic as possible and do not spoil important things.

This week I've concluded Unit 2 of CS101 Building Search Engine class. As a previous one it was very basic. We did went thought programming fundamentals on if statements, while loops, conditions and boolean operations. In contrast to Unit 1, I haven't got any really new information for me. All the information given very nicely, preparing listener to do some more serious stuff.

I think I started to get used to Python a little bit. Unfortunately I do not practice it much now, so I have to find simple project that I could accomplish in Python, besides the search engine. As always doing code katas is very nice for introduction to any new language, so I can do that.

Homework was simple enough, but again as last time I got one problem that made me think some extra time. This is "median search" issue. Say, you are given 3 numbers - (1,2,3). Median is the one between bigger and smaller number, in this case it's "2". In (9,3,6) it's "6" and in (7,8,7) it's "7". As a previous time I started with something I don't suppose to know, like lists and sorting. Solving this problem just with knowledge I got so far more problematic. So, I spent some time on that.. and was really happy than I found simple and nice solution for that. You should try to solve that, pretending you know only procedures and conditional operations.

Now, I'm looking forward for Unit 3. It's still basic, but there we suppose to create some simple crawler. I hope it will be fun!

JSON Model Binding to IDictionary<> is Broken

Yesterday, I've been creating small web service based on existing ASP.NET MVC infrastructure. The task was really simple. Web service itself should be just a proxy for existing internal API. The API method takes a Dictionary that contains some fields. So, I've created a data model like that.

public class Notification
{
 public int Id { get; set; }
 public string Recipient { get; set; }
 public IDictionary<string, string> Fields { get; set; }
}
    

and simple HttpPost handler, like

[HttpPost]
public ActionResult Send(string token, Notification notification)
{
    // ...
}
    

the payload posted to method is:

{"id":32,"recipient":"a@a.com","fields": { "EMAIL": "a@a.com"} }

    

I've tried to test the method, but the Fields property of model was always null. First I thought I got a problem somewhere in JSON payload, but after sometime I saw that everything is correct.

Google showed I'm not alone, so the issue been raised on SO. Darin Dimitrov responded that this is a bug of JsonValueProviderFactory. In the same time, some comments below contained the link for a bug reported, that was already stated as Fixed.

I forgot to mention that I did that stuff on ASP.NET MVC 2. I decided to try that on ASP.NET MVC 3, since I got the sources and if it works I can try to backport the fix into our MVC 2 infrastructure.

With my great disappointment it fails in exactly same way for ASP.NET MVC 3. That's not funny anymore. I blamed JavaScriptSerializer, JSON serializer that used inside the JsonValueProviderFactory that it simply not able to handle Dictionaries right. I knew that ASP.NET Web API is using Newtonsoft JSON.NET framework, which is really powerful for serialization/deserialization of JSON.

So, I run VS 2011 and create test ApiController that receives the model with IDictionary inside. What do you think happen? Ok, the model is no longer null, but it contains Dictionary with count of elements equals to zero. Fail.

public void Post(Notification notification)
{
    // ...
}
    

I re-raised issue again, now on ASP.NET Web Stack site on Codeplex. I also tried to quickly write the unit test that show the existence of problem, but it's not that easy to do that, so it requires some time. Hope I can do that later.

CS101 Building a Search Engine: Week 1

Disclaimer: this blog post expresses some impressions and details of Udacity CS101 "Building a Search Engine" online course. If you are either currently participating it or plan to do so in nearest future, this blog post could be a spoiler. Even though, I'm trying to make it generic as possible and do not spoil important things.

CS101 is fundamental course that supposes you have no background in programming at all. That's why all lectures was very-very basic and sometimes I felt really bored. If you fell the same, that's probably ok, since the most interesting stuff is about to start from Unit 3.

In the same time, for guys who has no programming skill's that might be even a little tough. To be honest, I had really tough moment during my first homework, that should not be a problem for professional programmer, but I'll describe it later.

Unit 1: Basics, Python, Numbers and Strings

What I understood from my entire career is that: backing to basics is always great. The years of enterprise development makes you strong in technologies and frameworks, but I managed to lost almost everything I got during my university days. Restoring that knowledge is very good brain exercise, constant repetition of basic is the way to mastery.

So, even that simple unit gave me a lot of things to remember, plus I learned some elementary of Python language.

Backus Naur Form

What was really interesting to me during Unit 1 is so called Backus-Naur Form, for describing the computer language grammar. This is a method of formalizing any (probably) computer language syntaxes. It has been invented by John Backus American scientist, how is famous as creator of FORTRAN and ALGOL computer languages, as well as his researches in functional programming.

Backus-Naur form is really simple and really powerful. It is described by the set of non-terminals and terminals. Each language expression is derived from BN form. Let's take and example,

<sentence> ::= <subject> <verb> <object>
        <subject> ::= <noun>
        <object> ::= <noun>
    

Here is the primitive BNF for English language. Each sentence in English should contain Subject, Verb, Object to be complete and have a meaning. Of course, BNF is not suppose to describe natural languages as English or Russian, since it much more complex.. but it works very fine with computer languages, which are strict. So, everything in brackets are so called non-terminals, it simply means that expression could not be terminated (completed) based on them. To complete we need terminals. Each non-terminal is replaced by terminal till it's done.

<sentence> ::= <subject> <verb> <object>
        <subject> ::= <noun>
        <object> ::= <noun>
        noun ::= I
        noun ::= Python
        noun ::= Cookies
        verb ::= Eat
        verb ::= Like
    

Now, the form is completed, so we can try to derive expression out of it. Let's try that. So, we start from the top line

<sentence> ::= <subject> <verb> <object>
    

Derive all non-terminals from expression

<sentence> ::= <noun> <verb> <noun>    
    

First "noun" is still non-terminal, so we proceed. Due to form, noun could be any of three (I, Python, Cookies) - so I can pick up any.

<sentence> ::= I <verb> <noun>    
    

"I" is the terminal, so we process next non terminal which is verb. Verb could be any of (Eat, Like). I'll take "Like".

<sentence> ::= I Like <noun>    
    

The last non-terminal is noun again. The same three options (I, Python, Cookies). Let's pick "Python".

<sentence> ::= I Like Python    
    

All non-terminals are replaced with terminals, that means we derieved the expression completely. Based on that simple algorithm I can derive other expressions that would be valid for that form.

<sentence> ::= I Like Cookies    
        <sentence> ::= I Like I    
        <sentence> ::= I Eat Python    
        <sentence> ::= Python Like Cookies
        <sentence> ::= Python Eat I
    

As you can see, some of them are completely non-sense, but still they are totally valid expressions. If you are curious, you can find BNF's for many know languages here.

Starting up Python

Start with Python programming language was one of my goals, dusted for quite long time on goals shelf. Hope that CS101 and further courses would be motivating enough to finally learn it. So, if you are like me - .NET, no Python background - don't worry, that's easy enough. Basically, all you need is Python interpreter and some text editor.

I really like Chocolatey for installing that stuff. Chocolatey is like NuGet package manager, but for software. I encourage you to try. So, instead of going to site, looking for latest version etc. I just opened my Power Shell command like and put:

cinst python
    

In 3 minutes, Python was on my machine.

The editor, you can pick up any you like. I prefer Sublime Text 2, it's really cool. Again, you can install it by Chocolatey.

cinst sublimetext2
    

After that you are almost Python developer. Just need to learn the language.

Strings, Find in strings

The rest of Unit 1, was mostly string operations in Python. And I was surprised how easy Python syntax is. First, you don't need to 'mark' varible declaration anyhow.. No types, no 'var' just the name and value.

s = "Hello World"
    

You can access each char inside the string just with [] operator.

s = "Hello World"
        print s[0]
    

It would print "H" char into console. It's not really cool, what cool is - substrings by index and negative indexes.

print s[0:5] # -> Hello
        print s[:5]  # -> Hello
        print s[6:]  # -> World
        print s[:]   # -> Hello World
        print s[-1]  # -> d
        print s[:-5] # -> Hello     
    

The find operation is very similar to what we have in C++ and C#. It, tried to find substring in string if it's find, position returned or -1.

print s.find('World') # -> 6
        print s.find('o')  # -> 4
        print s.find('o', 5) # -> 7
    

The last thing in the unit was str() method, that able convert any number (integer or float) into string representation.

print str(3.14)  # -> 3.14
        print str(100)  # -> 100
    

That's it. Based on that knowledge I suppose to complete my homework.

Homework

Again, as whole unit - there was really simple problems. The 'real' tough guy to me was very simple problem - "Rounding numbers". So, you are given with float number and you have to return it's integer representation. If numbers fraction is greater than 0.5, it should go ceil otherwise it goes floor. Not big deal I thought to my self and start to write code..

I spend around 10 minutes to create code like that:

number_as_string = str(x)
        dot_position = number_as_string.find('.')
        if dot_position != -1:
         integer_part = int(number_as_string[0:dot_position])
         decimal_part = int(number_as_string[dot_position + 1:])
         decimal_length = len(number_as_string[dot_position + 1:]) 
         dividor = pow(10, decimal_length - 1) * 5 

         if decimal_part >= dividor :
          integer_part += 1

         print integer_part
    

While writing that I had a bad feeling, that I'm using something that I'm not supposed to know, actually. The code worked and I submitted the solution. I received a response, that it actually giving right answer.. but, I was asked to create solution without if, int() or round().

Believe me or not, but I really frustrated on that task. I just didn't understood how it's possible to do not use any if here, but I have a condition inside the problem. I spend additional 10 minutes, starting to think it's just impossible. It's really funny, but indeed I thought it's something strange and had a great temptation to go and check for correct answer. Fortunately, I got this this online discussion (each course has it's discussion board, where student's can share the info). It turns out I'm not alone, some professional programmers did the look like I did with if's and calls to other functions.

Finally, I just tried to concentrate and really pretend to be a person how is just listen to that material first time, using the only knowledge I got in Unit 1. And solution came up to my mind! It was sooo easy, so I felt really ashamed for the code I wrote above. It's 3 lines of code, using just str() and find() method, so simple.

That was definitely facepalm situation. But, it really encourage me to continue!

I Enrolled to Udacity 'Build Search Engine' Online Course

I'm astonished how many opportunities we have now to learn and self-improve there days. One of the greatest things was announcement of online courses by Stanford. Stanford is the world class university with best professors and highest reputation. Then I first time heard that some of Stanford courses are online with videos, quizzes and materials - I thought to my self, - I would not miss the thing.

With a great support of Coursera and Udacity now we have great list of interesting courses, including programming, artificial intelligence, cryptography etc. Lead by well known specialists those courses are just price-less, nevertheless they are available for free.

I have enrolled for new course by Udacity - CS101: Building a Search Engine that has been started 16 Apr 2012, by David Evans and Sebastian Thrun. This should be interesting journey inside the web crawling, data mining, ranking etc. What is good for me it would not evolve hardcode-math and also does some good introduction into Python programming language. By the way, CS101 does not assume you know any computer language before or any special math knowledge. So, my assumptions that this course should not take hours of digging into the difference between o(n) and O(n) but rather has more practical aspects.

So, why I'm writing that?.. Millions of people are joining them, a lot of people already got successful records for several courses already. OK, let's look in eyes of truth. I enrolled for several ones already (ml-class and saas). But neither I successfully completed. Due to my business (read as laziness) I quickly went out of schedule and it was to difficult to line up again. I don't want it happen again.

I have some small goals for a next 7 weeks:


  • Start up learning new language

  • Lean something new in data mining and data processing

  • Improve my self learning discipline

  • Encourage myself for next online courses

I think CS101: Building a Search Engine is vey nice candidate, because:


  • As I said it should not include very complex math (that I already manage to forgot)

  • It has no strict deadlines for units

  • It is interesting enough to do not be bored in a middle (at least I hope so)

Moreover, I'll be doing a weekly blog post (Saturday) about highlighting the things I learned through week. If you are interested, please jump in since that train is still not gone. I'm sure it will be great experience.

Let's do that together!

ASP.NET Articles Mobile Application

Do you like asp.net web site content? Do you enjoy reading fine selected articles about ASP.NET and related technologies? Me too, but I spent most of the reading from my iPad. And unfortunately asp.net is not that mobile friendly yet, moreover articles are just a bunch of links to developers blogs, that might not so be adapted for mobile devices as well.

So, I would like to introduce mobile application that I created to close the gap. Please welcome http://aspnetmobile.apphb.com/.




aspnet.mobile is rather simple application. Despite of many similar apps that uses RSS channel, it goes for ASP.NET portal simple external API. RSS is bad in the way that you are limited with initial content (typically up to 25 articles on channel). With aspnet.mobile you freely can access any article ever posted on ASP.NET.

It's powered by jQuery Mobile that currently provides more "iOS-look" interface. I'm happy with that currently but I plan to have native look for Android and WP7 as well, so I thinking either to change the framework or to create custom one. But it currently looks and works great on iPad.




I didn't want to just refer reader to developers blog, for the reason above. Instead, I much inspired by iOS 5.0 Safari feature called 'Reader'. A bit of googling and I found that Safari using technology called Readability. There are different ports of that technology for a different platforms: Ruby, PHP, Python, Node.js.. and I was happy to find great implementation of NReadability by Marek Stoj. Basically, it allowed me to render nice looking pages, like:




Besides of that it has a basic support of offline mode. All read articles are stored in Local Storage, so once the application offine it will provide proper behavior and propose some content.

I will be happy if you try and let me know your impression. Feel free to check sources at github.

New in ASP.NET MVC4: Razor changes

Razor has been changed a little with ASP.NET MVC 4 beta. It's not a kind of radical changes, but rather improvements that make developers happier. As for me, developers happier then you need to write less code to get the same function. It reminded me a ideal device, which is part of TRIZ theory. Ideal device is a device that does not exit, but does it function. By analogy, ideal code is the code that not exist but it's function exist. Razor is not that ideal, through.. But it's "more ideal" than previous version.

No more @Url.Content

I got used to @Url.Content and used that for all CSS and JS references. Since it's to commonly used, developers decided to include it on a level of engine. Now, instead of

<script src="@Url.Content("~/Scripts/Controls.js")"></script>

You simply can write,

<script src="~/Scripts/Controls.js"></script>

If Razor detects ~/ it would created an output identical to @Url.Content. Just got rid of several bytes within view files.

Conditions

Conditions in attributes were pretty noisy. Have you ever create something like this?

<div @{if (myClass != null) { <text>class="@myClass"</text> } }>Content</div>

I had and I did not like it much. I usually ended up with creation of some simple HTML helper instead. With new Razor it a little simpler, not you can write

<div class="@myClass">Content</div>

If @myClass is null, it won't output class attribute at all. Very handy.

And a little more

This is an update section I created after this post has been twitted by Scott Guthrie and some valuable comments has been received.

Brad Wilson stated, conditions does not only support nullable types, but also booleans. Say, I have code:

<input checked="@ViewBag.Checked" type="checkbox"/>

If the @ViewBag.Checked in null or false, it will be rendered as:

<input type="checkbox"/>

Else if @ViewBag.Checked is true, it will be rendered as:

<input checked="checked" type="checkbox"/>

Erik Porter also mentioned the custom support for data-* attributes. Data attributes are little special, so even if you missing particular value you still want to have those as empty data-role = "". So, if you have code like:

<ul data-role="@ViewBag.ListRole">
</ul>

and @ViewBag.ListRole is null or false, data attribute will be eliminated. That's how it work in Beta. But for next releases data-* attributes will be treated specially, so even if value is null or false they will be rendered as empty ones.

Conclusions

I haven't noticed any more changes so far. It's great to see that Razor has not been "frozen" and still improving. I like that view engine first of all by it's simplicity. So making it even more simple would definitely make it more attractive.

Why I'm Not Using Bundling.. Yet

Last time I a posted some initial info about Bundling and Minification abilities of MVC4. In this post, I describe some concerns that prevents me of using it right now. Let me remind that I'm doing review of MVC 4 beta and I hope some of those concern would not be actual at the time of release. This is only personal considerations, you might not agree with everything here.

It's contra-intuitive

Maybe the 'contra-intuitive' is not exact word that reflects my frustration. What I mean, it does not do what you might expect by default. Remember I described two methods RegisterTemplateBundles() and EnableDefaultBundles()? It was really unclear to me what they do until I looked into code. Modern frameworks tend to be as less surprise as possible, but not in case of System.Web.Optimizations.

Development and production mode

The fact it does not take into account 'Debug' and 'Release' mode is also very confusing. As same as in point above, I have a different expectations how it should behave. For 'Debug' mode it simply should do nothing - no optimization, no compression. For release mode it should do as much as possible to minify the number of HTTP request. It turns out that you have to create some code on your own to make it happen.

Bundling is bad during debugging

While you in development mode you do debug, no surprise here. Having FireBug or Chrome Development tools it's very easy to debug javascript, you can pick up any file and place breakpoint inside.


chrome development

It is no so easy with bundling, cause it will package all your files in one big chunk, so you need to open and find right place there. Since the total number of line could be huge there, it's turns to be big deal.

As a workaround you have to have a copies of references, one you using on development and ones you use on production.

<!-- Development -->
<script type="text/javascript" src="~/Scripts/jquery-1.6.4.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.mobile-1.0b3.js"></script>
<script type="text/javascript" src="~/Scripts/knockout-2.0.0.js"></script>
<script type="text/javascript" src="~/Scripts/underscore.js"></script>
<script type="text/javascript" src="~/Scripts/App/CacheInit.js"></script>     

<!-- Production 
<script type="text/javascript" src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Scripts/js")"></script>
-->

It's not well ironed

Since it's very young obviously it has some problems.

Be honest, I haven't seen on my own but one of the comments in my previous post described the issue with minification of CSS files that include -ie- specific selectors. That's probably not only one issue found.

What did I expect?

To do not have only critics I try to put some constructive part in post as well. Ok, so I see it should work to meet my needs?

First of all, it should be implemented as simple HTML razor helpers. You just specify the name of bundle there, like "scripts/js" and that's it. Helper is smart enough to understand what is active environment at the moment. In case of 'Debug' it expanded to a bunch of script references or links, for JS and CSS respectively. In 'Release' mode it's indeed refers the bundle, so it's packaged and minified for best performance.

You might say, that 1. this is out of scope for System.Web.Optimization framework 2. you can create this behavior easily on your own. This is right, but in the same time if you deal with ASP.NET MVC4 you have some expectation that is should work right and you are not forced to invent the wheel again, so you have kind of consistency between numerous projects.

I've been thinking about to create something like that, but during the chat with fellow developer @andrexx about bundling and he showed me something interesting. Tom DuPont has already implemented something that's really reflects my needs. It's the way of configuring bundles both from code and web.config. It looks like a very handy tool.

New in ASP.NET MVC4: Bundling and Minification

Next new feature that appeared in MVC 4 beta is bundling and minification. Idea is simple: modern web application contains of many static resources, especially css and javascript files. To load the page browser have to load each resource. Each resource is being requested by HTTP request. Browser have to make as many request as page refers, wait till all are completed and only after that render the page.

The problem is, each HTTP request takes time. One of the most critical Yahoo web applications performance recommendation says - Minimize HTTP request. As few HTTP requests you need to load application as better.

System.Web.Optimization

Bundling and minification is located in it's own namespace System.Web.Optimization and resides in assembly named Microsoft.Web.Optimization, which is installed by default with new ASP.NET MVC4 application template as NuGet package. Since it's still in beta, namespaces and class names are probably be changing, but let's look on that we have now.

What is bundle?

Bundle is simply logical group of files that could be referenced by unique name and being loaded with one HTTP request. Suppose, we have a Layout.cshtml that might look something like that:

<meta charset="utf-8" />

<title>@ViewBag.Title</title> 
        
<link rel="stylesheet" href="~/Content/jquery.mobile-1.0b3.min.css" />
<link rel="stylesheet" href="~/Content/reset.css" />
<link rel="stylesheet" href="~/Content/foundation.css" />
<link rel="stylesheet" href="~/Content/Fonts.css" />
<link rel="stylesheet" href="~/Content/Site.Layout.css" />
<link rel="stylesheet" href="~/Content/Site.Mobile.css" />

<script type="text/javascript" src="~/Scripts/jquery-1.6.4.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.mobile-1.0b3.js"></script>
<script type="text/javascript" src="~/Scripts/knockout-2.0.0.js"></script>
<script type="text/javascript" src="~/Scripts/underscore.js"></script>
<script type="text/javascript" src="~/Scripts/App/CacheInit.js"></script>        

You can see, that's a lot of css and javascript that will be loaded for page. With bundling we can rewrite it with very simple code

<meta charset="utf-8" />

<title>@ViewBag.Title</title> 
        
<link rel="stylesheet" href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Content/css")" />

<script type="text/javascript" src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Scripts/js")"></script>

In this case "~/Content/css" and "~/Scripts/js" are no longer virtual paths, but bundle names.

The the browser would load this page, rendered HTML would look like:

<link href="/Content/css?v=q_sftc19r22licIM8-Ar58FwviyWry1JuYbA-iATm4M1" rel="stylesheet" type="text/css" />
<script src="/Scripts/js?v=_8kyYWxz-Je_VE0p3_w5nbcjAhq0Qj4vZiNxvYU_oBg1"></script>

Note, it would reference the bundle with version. The version is a kind of hash taken on all files in bundle content. This enables browser caching, if content of bundle is not change browser will take it from cache, which is much faster. In case of changes, new version token is generated, so browser would be forced to reload bundle.


chrome development tools

Bundle registration

In global.asax file you will see new line:

    BundleTable.Bundles.RegisterTemplateBundles();

It's only one small line of code that enables bundling and minification framework.

RegisterTemplateBundles() vs. EnableDefaultBundles()

It looks fine so far, so I tried to add new javascript file into Scripts folder. Unfortunately, my application did not work. I think this is first very contra-intuitive fact of bundling framework. Googling a bit I found quick solution, change RegisterTemplateBundles() to EnableDefaultBundles().. I tried that and it really works.

Since the System.Web.Optimization has not been opened sourced yet (in case you haven't heard - ASP.NET web stack is open source, even with accepting pull request) I had to go to JustDecompile to understand why is that.

So, RegisterTemplateBundles() is looks like that,

public void RegisterTemplateBundles()
{
    bool flag;
    bool flag2;
    bool flag3;
    bool flag4;
    bool flag5;
    bool flag6;
    bool flag7;
    Bundle bundle1 = new Bundle("~/Scripts/js", new JsMinify());
    bool flag8 = false.AddDirectory("~/Scripts", "jquery-*", flag, flag8);
    bool flag9 = false.AddDirectory("~/Scripts", "jquery.mobile*", flag2, flag9);
    bool flag10 = false.AddDirectory("~/Scripts", "jquery-ui*", flag3, flag10);
    bool flag11 = false.AddDirectory("~/Scripts", "jquery.unobtrusive*", flag4, flag11);
    bool flag12 = false.AddDirectory("~/Scripts", "jquery.validate*", flag5, flag12);
    bool flag13 = false.AddFile("~/Scripts/MicrosoftAjax.js", flag13);
    bool flag14 = false.AddFile("~/Scripts/MicrosoftMvc.js", flag14);
    bool flag15 = false.AddDirectory("~/Scripts", "modernizr*", flag6, flag15);
    bool flag16 = false.AddFile("~/Scripts/AjaxLogin.js", flag16);
    this.Add(bundle1);
    Bundle bundle2 = new Bundle("~/Content/css", new CssMinify());
    bool flag17 = false.AddFile("~/Content/site.css", flag17);
    bool flag18 = false.AddDirectory("~/Content/", "jquery.mobile*", flag7, flag18);
    this.Add(bundle2);
    Bundle bundle3 = new Bundle("~/Content/themes/base/css", new CssMinify());
    bool flag19 = false.AddFile("~/Content/themes/base/jquery.ui.core.css", flag19);
    bool flag20 = false.AddFile("~/Content/themes/base/jquery.ui.resizable.css", flag20);
    bool flag21 = false.AddFile("~/Content/themes/base/jquery.ui.selectable.css", flag21);
    bool flag22 = false.AddFile("~/Content/themes/base/jquery.ui.accordion.css", flag22);
    bool flag23 = false.AddFile("~/Content/themes/base/jquery.ui.autocomplete.css", flag23);
    bool flag24 = false.AddFile("~/Content/themes/base/jquery.ui.button.css", flag24);
    bool flag25 = false.AddFile("~/Content/themes/base/jquery.ui.dialog.css", flag25);
    bool flag26 = false.AddFile("~/Content/themes/base/jquery.ui.slider.css", flag26);
    bool flag27 = false.AddFile("~/Content/themes/base/jquery.ui.tabs.css", flag27);
    bool flag28 = false.AddFile("~/Content/themes/base/jquery.ui.datepicker.css", flag28);
    bool flag29 = false.AddFile("~/Content/themes/base/jquery.ui.progressbar.css", flag29);
    bool flag30 = false.AddFile("~/Content/themes/base/jquery.ui.theme.css", flag30);
    this.Add(bundle3);
}

As you can see it adds all recourses that came just in template, including jQuery Mobile and jQuery UI.

In the same time, EnableDefaultBundles()

public void EnableDefaultBundles()
{
    this.Add(new DynamicFolderBundle("js", JsMinify.Instance, "*.js"));
    this.Add(new DynamicFolderBundle("css", CssMinify.Instance, "*.css"));
}

So, what it does - it matches all javascript and css files in project, minify them and create to bundles out of it.

As you can see EnableDefaultBundles() is also uses Minification policy for bundle content.

How add my own custom bundle?

As simple as create new Bundle object, put files inside and then add it to Bundles collection.

var bundle = new Bundle("~/Scripts/libs", new JsMinify());
bundle.AddFile("~/Scripts/knockout-2.0.0.js");
BundleTable.Bundles.Add(bundle);

But there two issues here. First of all, you don't always want to minify. Second, adding bundles with many files will make global.aspx.cs looks messy. I really liked approached proposed by Scott K. Allen in his Yet Another Bundling Approach for MVC 4 blog post. He does it in more object-oriented way including smart code to decide, should the bundle be minified or not. All you need is just take code he created and after you are able to make bundles like that.

public class JsLibsBundle : JsBundle
{
    public JsLibsBundle() : base("~/js/libs")
    {
        AddFiles(
            "~/Scripts/jquery-1.6.4-vsdoc.js",
            "~/Scripts/jquery-1.6.4.js",
            "~/Scripts/jquery.mobile-1.0b3.js",
            "~/Scripts/knockout-2.0.0.js",
            "~/Scripts/modernizr-2.0.6-development-only.js",
            "~/Scripts/underscore.js"
        );
    }
}

public class CssAppBundle : CssBundle
{
    public CssAppBundle() : base("~/css/mobile")
    {
        AddFiles(
            "~/Content/jquery.mobile-1.0b3.css",
            "~/Content/Site.Mobile.css"
        );
    }
}

And put them to registered those classes in global.asax.cs

    BundleTable.Bundles.Add(new JsLibsBundle());
    BundleTable.Bundles.Add(new CssAppBundle());

Ok, how all that stuff works?

Now let's do a really brief look under the hood. Again, JustDecompile is our friend here.

It was interesting to me to find out new cool way of registration modules in ASP.NET. No longer entry points in web.config or other magic. You can have a special class PreApplicationStartCode that would be called then assembly is loaded, but before application is stated.

public static class PreApplicationStartCode
{
    private static bool _startWasCalled;

    public static void Start();
}

Here System.Web.Optimization register it's own module, called BundleModule.

public static void Start()
{
    if (PreApplicationStartCode._startWasCalled)
    {
        return;
    }
    PreApplicationStartCode._startWasCalled = 1;
    DynamicModuleUtility.RegisterModule(typeof(BundleModule));
}

Then the module is intialized, it subscribes for event called HttpApplication.PostResolveRequestCache and inside the callback it would register the BundleHandler.

private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
{
    HttpApplication httpApplication = (HttpApplication)sender;
    if (BundleTable.Bundles.Count > 0)
    {
        BundleHandler.RemapHandlerForBundleRequests(httpApplication);
    }
}

The handler is now responsible for dirty job. Through the RequestBundle class it finally comes to ProcessRequest method.

internal void ProcessRequest(BundleContext context)
{
    context.EnableInstrumentation = Bundle.GetInstrumentationMode(context.HttpContext);
    BundleResponse bundleResponse = this.GetBundleResponse(context);
    Bundle.SetHeaders(bundleResponse, context);
    context.HttpContext.Response.Write(bundleResponse.Content);
}

So, the GetBundleResponse is there magic is happens.

private BundleResponse GetBundleResponse(BundleContext context)
{
    BundleResponse bundleResponse = Bundle.CacheLookup(context);
    if (bundleResponse == null || context.EnableInstrumentation)
    {
        bundleResponse = this.GenerateBundleResponse(context);
        if (!context.EnableInstrumentation)
        {
            Bundle.UpdateCache(context, bundleResponse);
        }
    }
    return bundleResponse;
}

What's important here is that it uses cache. So, it makes bundling rather efficient. In case if there are no cached result, it will run the GenerateBundleResponse to generate actual response:

public virtual BundleResponse GenerateBundleResponse(BundleContext context)
{
    if (context == null)
    {
        throw new ArgumentNullException("context");
    }
    IEnumerable<FileInfo> fileInfos = this.EnumerateFiles(context);
    fileInfos = context.BundleCollection.IgnoreList.FilterIgnoredFiles(fileInfos);
    fileInfos = this.Orderer.OrderFiles(context, fileInfos);
    fileInfos = this.ReplaceFileExtensions(context, fileInfos);
    string str = this.Builder.BuildBundleContent(this, context, fileInfos);
    BundleResponse bundleResponse = new BundleResponse(str, fileInfos);
    this.Transform.Process(context, bundleResponse);
    return bundleResponse;
}

Yet another interesting finding here is this.Orderer. Sometime ago I did smalltalk on Kiev ALT.NET meeting about new stuff in VS2011 and being asked a question, how is possible to order the files. I didn't know answer then. It is actually possible to setup the order of files inside bundle, in case you have cross-file dependencies:

public interface IBundleOrderer
{
 IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files);
}

That's it, the generated response than just being written to context.HttpContext.Response.

Conclusions

Bundling and minification is something that I personally wanted so much, to appear in new MVC framework. Now it's there, it works.. but I would not say I'm 100% happy. There are several things that makes it a little difficult to use, as for me. I did want to place it in this post, but appeared to big.. So, I'll probably do a separate one on this matter.