<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Kazi Manzur Rashid's Blog</title><link>http://weblogs.asp.net/rashid/default.aspx</link><description>Sharing Thoughts and Learning</description><dc:language>en</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/kazimanzurrashid" type="application/rss+xml" /><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fkazimanzurrashid" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fkazimanzurrashid" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Fkazimanzurrashid" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/kazimanzurrashid" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fkazimanzurrashid" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fkazimanzurrashid" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fkazimanzurrashid" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2Fkazimanzurrashid" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fkazimanzurrashid" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare href="http://www.yourminis.com/subscribe.aspx?u=http%3A%2F%2Ffeeds.feedburner.com%2Fkazimanzurrashid" src="http://www.yourminis.com/images/addtoyourminisbadge.gif">Subscribe with Yourminis.com</feedburner:feedFlare><feedburner:feedFlare href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fkazimanzurrashid" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item><title>Telerik Extensions for ASP.NET MVC Survey</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/McaHQdiB5oA/telerik-extensions-for-asp-net-mvc-survey.aspx</link><pubDate>Mon, 16 Nov 2009 19:19:05 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7256927</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>0</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7256927</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7256927</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/11/17/telerik-extensions-for-asp-net-mvc-survey.aspx#comments</comments><description>&lt;p&gt;Dear readers, as you know that we have released &lt;a href="http://weblogs.asp.net/rashid/archive/2009/11/05/using-telerik-mvc-grid-in-crud-scenario.aspx" target="_blank"&gt;our beta&lt;/a&gt; few weeks back, we are currently looking for your feedback on the existing features as well as the features that you would like to see in our next release. This is a very short survey only 4/5 screens to complete, &lt;a href="http://survey.telerik.com/Survey.aspx?s=f565c7b942344c6887300e7a060db897" target="_blank"&gt;click here to submit your valuable feedback&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Thanks in advance for your precious time.&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f11%2f17%2ftelerik-extensions-for-asp-net-mvc-survey.aspx&amp;amp;title=Telerik+Extensions+for+ASP.NET+MVC+Survey"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/11/17/telerik-extensions-for-asp-net-mvc-survey.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7256927" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/McaHQdiB5oA" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Telerik/default.aspx">Telerik</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/11/17/telerik-extensions-for-asp-net-mvc-survey.aspx</feedburner:origLink></item><item><title>ASP.NET MVC View and Transaction</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/gYfJRptSepw/asp-net-mvc-view-and-transaction.aspx</link><pubDate>Wed, 11 Nov 2009 07:19:05 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7251174</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>17</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7251174</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7251174</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/11/11/asp-net-mvc-view-and-transaction.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://weblogs.asp.net/srkirkland/archive/2009/11/10/inserting-transactions-into-telerik-s-asp-net-mvc-grid.aspx" target="_blank"&gt;Scott showed&lt;/a&gt; how to render the Grid in a Transaction. Certainly it does the job but in my opinion view component should not be responsible for this kind of cross cutting concerns, instead we can use the Action Filters. Lets see how we can utilize the Action Filter in this scenario instead of modifying the Grid code. What Scott is trying to do is encapsulate the data access operation in a transaction, the Action Filter has several methods which the ASP.NET MVC framework executes in different stages of a request. In this case, we will use the &lt;code&gt;OnActionExecuting&lt;/code&gt; which fires before the code enters into the controller method to start a transaction and &lt;code&gt;OnResultExecuted&lt;/code&gt; which fires when the view is processed, we will commit/rollback based upon the status, here is the code that would process the action result in a transaction:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:b8db9b5f-8559-4635-b81e-adeb02347a87" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace AltNorthwind
{
    using System.Web.Mvc;
    using System.Transactions;

    public class TransactionAttribute : ActionFilterAttribute
    {
        private CommittableTransaction transaction;

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            transaction = new CommittableTransaction();

            base.OnActionExecuting(filterContext);
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            base.OnResultExecuted(filterContext);

            try
            {
                if ((filterContext.Exception != null) &amp;amp;&amp;amp; (!filterContext.ExceptionHandled))
                {
                    transaction.Rollback();
                }
                else
                {
                    transaction.Commit();
                }
            }
            finally
            {
                transaction.Dispose();
            }
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Next, we will decorate the Controller Action method with this attribute like the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:58578c69-2996-4a03-ad8b-c3408fa20b24" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;[Transaction]
public ActionResult Index()
{
    return View(repository.All());
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Hope, you would find it useful.&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f11%2f11%2fasp-net-mvc-view-and-transaction.aspx&amp;amp;title=ASP.NET+MVC+View+and+Transaction"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/11/11/asp-net-mvc-view-and-transaction.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7251174" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/gYfJRptSepw" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Action+Filter/default.aspx">Action Filter</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/11/11/asp-net-mvc-view-and-transaction.aspx</feedburner:origLink></item><item><title>Web Asset Enhancements in Telerik Extensions for ASP.NET MVC</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/0TjKIgtXbno/web-asset-enhancements-in-telerik-extensions-for-asp-net-mvc.aspx</link><pubDate>Mon, 09 Nov 2009 07:28:38 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7249575</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>14</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7249575</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7249575</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/11/09/web-asset-enhancements-in-telerik-extensions-for-asp-net-mvc.aspx#comments</comments><description>&lt;p&gt;&lt;strong&gt;[Updated: Source code attached]&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In the recent release, there has been few enhancements in the Web Asset Management. One of the new thing that we introduced which was actually requested by the community is Shared Web Asset. In this post, I will show you, how to use it in your ASP.NET MVC Application.&lt;/p&gt;  &lt;p&gt;In the previous version, you can only define the web assets either in the &lt;code&gt;ScriptRegistrar&lt;/code&gt; or &lt;code&gt;StyleSheetRegistrar&lt;/code&gt; like the following:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:a9785c61-7726-48fe-9200-e7d99f84ad3d" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.Telerik()
       .ScriptRegistrar()
       .Scripts(scripts =&amp;gt;
                scripts.AddGroup("myScripts",
                                  group =&amp;gt; group.Add("script1.js")
                                                .Add("script2.js")
                                                .Add("script3.js")
                                                .Combined(true)
                                                .Compress(true)
                                )
               )
       .Render();%&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;if you want to reuse it in another page, you have to copy the exact same thing. Also the url that it generates is bit cryptic and very long, for example for the above the following html snippet is generated:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:0f411aa6-8049-43b8-97a2-e62e7976de3f" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;script type="text/javascript" src="http://weblogs.asp.net/asset.axd?id=rgAAAB-LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee--997o7nU4n99__P1xmZAFs9s5K2smeIYCqyB8_fnwfPyJ-8UfT9qNHH2WrVVlMs7aolnffbf90dpk107pYtR-NPrqkr_d2dh6O7413d3fujXfos-lHj9p6ndMvs48e3fv0_ugj-vm9X_zRitq-5hcbanXOn1UfPdoZfbSkbwTk7vinm49-yYi_2PW_2PO-2PO_uMdffP-XfP-X_D-iwlMArgAAAA%3d%3d"&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After evaluating quite a different scenarios, we found that we have to include the complete details of the web assets in the script/stylesheet url and this is the reason the url becomes long and cryptic. Behind the scene, we are serializing and compressing the web asset group and then writing it as a base64 encoded string in the page.&lt;/p&gt;

&lt;p&gt;With our new Shared Web Asset, you will not only be able to share the same web assets across the different pages, you will also be able to control the generated urls. There are two ways you can define the shared web assets, through the configuration file or with the fluent syntax. First, lets see, how you can define it the in the configuration file.&lt;/p&gt;

&lt;p&gt;For example, for the above web assets we can declare it in the &lt;code&gt;web.config&lt;/code&gt; file like the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:842a56b1-4c5c-45db-85de-dbe37f1bc4b3" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;configuration&amp;gt;
    &amp;lt;configSections&amp;gt;
        &amp;lt;sectionGroup name="telerik"&amp;gt;
            &amp;lt;section name="webAssets" type="Telerik.Web.Mvc.Configuration.WebAssetConfigurationSection, Telerik.Web.Mvc"/&amp;gt;
        &amp;lt;/sectionGroup&amp;gt;
    &amp;lt;/configSections&amp;gt;
    &amp;lt;telerik&amp;gt;
        &amp;lt;webAssets&amp;gt;
            &amp;lt;scripts&amp;gt;
                &amp;lt;add name="myScripts" combined="true" compress="true" enabled="true"&amp;gt;
                    &amp;lt;items&amp;gt;
                        &amp;lt;add source="script1.js"/&amp;gt;
                        &amp;lt;add source="script2.js"/&amp;gt;
                        &amp;lt;add source="script3.js"/&amp;gt;
                    &amp;lt;/items&amp;gt;
                &amp;lt;/add&amp;gt;
            &amp;lt;/scripts&amp;gt;
        &amp;lt;/webAssets&amp;gt;
    &amp;lt;/telerik&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Or you can place it the &lt;code&gt;global.asax&lt;/code&gt; like the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:4c072f26-2988-47e1-a2a1-5df22ec38098" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);

    SharedWebAssets.Scripts(scripts =&amp;gt;
                            scripts.AddGroup("myScripts",
                                              group =&amp;gt; group.Add("Script1.js")
                                                            .Add("Script2.js")
                                                            .Add("Script3.js")
                                                            .Combined(true)
                                                            .Compress(true)
                                            )
                           );
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, use the &lt;code&gt;AddSharedGroup&lt;/code&gt; of the &lt;code&gt;ScriptRegistrar&lt;/code&gt; like the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:cbedce06-e8d0-46d2-9d28-098a6eebeb14" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.Telerik()
       .ScriptRegistrar()
       .Scripts(scripts =&amp;gt; scripts.AddSharedGroup("myScripts"))
       .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And it would render the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:436a9b51-c5a4-41e4-b106-8ed3413d8537" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;script type="text/javascript" src="http://weblogs.asp.net/asset.axd?id=myScripts"&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can also mix the configuration file and fluent syntax, in that case, the configuration file assets will be registered first and then the fluent syntax.&lt;/p&gt;

&lt;p&gt;Before completing this post, I would like to mention one more feature, though it was available from the CTP release. If you have downloaded the release zip file, in the Example Project, you have seen, we have placed the css and js files under the “2009.3.1103.0” folder in there corresponding assets folders. The “2009.3.1103.0” is actually the version number of our component. When locating any asset the version number folder is first scanned for the requested asset name, if it does not exist, it search its parent folder which is Content for css and Scripts for the js files. The next rule is whether the application is running in debug or release mode (&lt;code&gt;compilation debug=&amp;quot;true&amp;quot;&lt;/code&gt; in &lt;code&gt;web.config&lt;/code&gt; file), when the application is running in debug mode, and lets say the assets is script1.js, then it will be searched in the following order:&lt;/p&gt;

&lt;p&gt;1. script1.debug.js 
  &lt;br /&gt;2. script1.js 

  &lt;br /&gt;3. script1.min.js 

  &lt;br /&gt;

  &lt;br /&gt;and in the release mode:&lt;/p&gt;

&lt;p&gt;1. script1.min.js 
  &lt;br /&gt;2. script1.js 

  &lt;br /&gt;3. script1.min.js&lt;/p&gt;

&lt;p&gt;And this is the reason our examples, we did not mention the actual file name, instead we depend on the framework to resolve it based upon the runtime environment and don’t worry about the performance, in the release mode the resolve logic gets only executed when the asset is accessed for the first time and then we cache the resolve path for the consequent request.&lt;/p&gt;

&lt;p&gt;That’s it for today. &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download:&lt;/strong&gt; &lt;a href="http://weblogs.asp.net/blogs/rashid/SharedWebAsset.zip" target="_blank"&gt;SharedWebAsset.zip&lt;/a&gt;&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f11%2f09%2fweb-asset-enhancements-in-telerik-extensions-for-asp-net-mvc.aspx&amp;amp;title=Web+Asset+Enhancements+in+Telerik+Extensions+for+ASP.NET+MVC"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/11/09/web-asset-enhancements-in-telerik-extensions-for-asp-net-mvc.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7249575" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/0TjKIgtXbno" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Telerik/default.aspx">Telerik</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/11/09/web-asset-enhancements-in-telerik-extensions-for-asp-net-mvc.aspx</feedburner:origLink></item><item><title>Using Telerik MVC Grid in CRUD Scenario</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/a_Qi51PcovQ/using-telerik-mvc-grid-in-crud-scenario.aspx</link><pubDate>Thu, 05 Nov 2009 11:41:19 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7247727</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>15</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7247727</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7247727</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/11/05/using-telerik-mvc-grid-in-crud-scenario.aspx#comments</comments><description>&lt;p&gt;I am proud to inform you that yesterday we released our Q3 2009 version of Telerik Extensions for ASP.NET MVC. As promised this release includes:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Grid &lt;/li&gt;    &lt;li&gt;Menu &lt;/li&gt;    &lt;li&gt;PanelBar &lt;/li&gt;    &lt;li&gt;TabStrip &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;You can find the live version and source codes in the following locations:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://demos.telerik.com/aspnet-mvc/" target="_blank"&gt;Live Version&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://telerikaspnetmvc.codeplex.com/SourceControl/changeset/view/35535" target="_blank"&gt;Source Code&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Also checkout the product &lt;a href="http://www.telerik.com/products/aspnet-mvc.aspx" target="_blank"&gt;home page&lt;/a&gt; and part-II of &lt;a href="http://telerikwatch.com/2009/11/telerik-extensions-for-mvc-unofficial.html" target="_blank"&gt;Tod’s unofficial faq&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;In this post, I will show you how to create a basic CRUD(Create/Read/Update/Delete) application with our new MVC Grid. I will be using both Entity Framework v1.0 with the default web form view engine and NHibernate with Spark to create the CRUD screens for the Customer table of Northwind database. &lt;/p&gt;  &lt;p&gt;Lets start with the Entity Framework and Default View Engine.&lt;/p&gt;  &lt;p&gt;First, lets create a new ASP.NET MVC application and name it as Northwind, when Visual Studio prompts you for the Unit Test project, just skip it. Now, right click the Models folder and add an Entity Data Model and name it as Database. Next, drag the Customers table of the Northwind database from Server Explorer in the VS design surface.&lt;/p&gt;  &lt;p&gt;Now, we will create a generic repository to access the database, lets define the interface first.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:e51b91bd-51b0-465d-9932-db532a876709" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public interface IRepository&amp;lt;TEntity, TId&amp;gt;
{
    void Add(TEntity entity);

    void Delete(TId id);

    TEntity Get(TId id);

    IEnumerable&amp;lt;TEntity&amp;gt; All();
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And the implementation:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:62da7cf2-a322-4572-88cc-1a30cc2d5c67" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class Repository&amp;lt;TEntity, TId&amp;gt; : IRepository&amp;lt;TEntity, TId&amp;gt;
{
    private readonly Database database;

    public Repository() : this(EntityFrameworkObjectContextPerRequest.CurrentDatabase)
    {
    }

    public Repository(Database database)
    {
        this.database = database;
    }

    public void Add(TEntity entity)
    {
        database.AddObject(TypeName(), entity);
    }

    public void Delete(TId id)
    {
        database.DeleteObject(Get(id));
    }

    public TEntity Get(TId id)
    {
        var typeName = TypeName();

        var keyName = database.MetadataWorkspace
                              .GetItems&amp;lt;EntityType&amp;gt;(DataSpace.CSpace)
                              .Single(meta =&amp;gt; meta.Name == typeName)
                              .KeyMembers[0].Name;

        var param = Expression.Parameter(typeof(TEntity), "x");
        var left = Expression.Property(param, keyName);
        var right = Expression.Constant(id);
        var equal = Expression.Equal(left, right);

        var predicate = Expression.Lambda&amp;lt;Func&amp;lt;TEntity, bool&amp;gt;&amp;gt;(equal, param).Compile();

        return All().SingleOrDefault(predicate);
    }

    public IEnumerable&amp;lt;TEntity&amp;gt; All()
    {
        return database.CreateQuery&amp;lt;TEntity&amp;gt;("[" + TypeName() + "]");
    }

    private static string TypeName()
    {
        return typeof(TEntity).Name;
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Very basic stuff,except the &lt;code&gt;Get()&lt;/code&gt; method, since we are creating a generic repository which entity’s identifier is not known, we are using the Entity Framework meta data for building the identifier lambda expression. Please note that the stuffs that I have shown in the above has nothing to do with our Grid, we can directly use the Entity Framework &lt;code&gt;ObjectContext&lt;/code&gt; in our &lt;code&gt;Controller&lt;/code&gt; instead of this repository. &lt;/p&gt;

&lt;p&gt;Now, right click the Controllers folder and a new Controller named &lt;code&gt;CustomerController&lt;/code&gt; with the following code:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:1fc5b1f6-060c-46f8-b8af-63a09c18ea24" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;[HandleError]
public class CustomerController : Controller
{
    private readonly IRepository&amp;lt;Customers, string&amp;gt; repository;

    public CustomerController() : this(new Repository&amp;lt;Customers, string&amp;gt;())
    {
    }

    public CustomerController(IRepository&amp;lt;Customers, string&amp;gt; repository)
    {
        this.repository = repository;
    }

    public ActionResult Index()
    {
        return View(repository.All());
    }

    public ActionResult Details(string id)
    {
        return View(repository.Get(id));
    }

    public ActionResult Create()
    {
        return View();
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create([Bind(Exclude = "CustomerId")]Customers customer)
    {
        customer.CustomerID = CreateNewId();
        repository.Add(customer);

        return RedirectToAction("Index");
    }

    public ActionResult Edit(string id)
    {
        return View(repository.Get(id));
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(string id, FormCollection collection)
    {
        var customer = repository.Get(id);

        UpdateModel(customer, collection.ToValueProvider());

        return RedirectToAction("Index");
    }

    public ActionResult Delete(string id)
    {
        return View(repository.Get(id));
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Delete(string id, string confirm)
    {
        repository.Delete(id);

        return RedirectToAction("Index");
    }

    // Not a bullet proof method, but it should work for the demo
    private string CreateNewId()
    {
        Func&amp;lt;int, string&amp;gt; generateId = length =&amp;gt;
                                       {
                                           string generatingId = string.Empty;
                                           Random rnd = new Random();

                                           for (int i = 1; i &amp;lt;= length; i++)
                                           {
                                               int characterCode = rnd.Next(65, 90); // Only uppercase;
                                               generatingId += Convert.ToChar(characterCode).ToString();
                                           }

                                           return generatingId;
                                       };

        string id = generateId(5);

        while (repository.Get(id) != null)
        {
            id = generateId(5);
        }

        return id;
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are one more thing we have to do before we start working on the Views, as you can see in the above the &lt;code&gt;Repository&lt;/code&gt; uses a special class &lt;code&gt;EntityFrameworkObjectContextPerRequest&lt;/code&gt; in the constructor to get the &lt;code&gt;Database&lt;/code&gt; reference. &lt;code&gt;EntityFrameworkObjectContextPerRequest&lt;/code&gt; is a &lt;code&gt;HttpModule&lt;/code&gt; which creates a new instance of the &lt;code&gt;Database&lt;/code&gt; in the &lt;code&gt;BeginRequest&lt;/code&gt; and stores it in the &lt;code&gt;HttpContext.Items&lt;/code&gt; to reuse it in the same request and in the &lt;code&gt;EndRequest&lt;/code&gt; it commit the changes and &lt;code&gt;Dispose&lt;/code&gt; the &lt;code&gt;Database&lt;/code&gt; instance. Here is the code:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:85e39fb2-f99b-4c2c-9d82-e4ba8193f235" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class EntityFrameworkObjectContextPerRequest : IHttpModule
{
    private static readonly string key = typeof(Database).FullName;

    public static Database CurrentDatabase
    {
        get
        {
            return HttpContext.Current.Items[key] as Database;
        }
    }

    public void Init(HttpApplication context)
    {
        context.BeginRequest += OnBeginRequest;
        context.EndRequest += OnEndRequest;
    }

    public void Dispose()
    {
    }

    private static void OnBeginRequest(object sender, EventArgs e)
    {
        var database = HttpContext.Current.Items[key] as Database;

        if (database == null)
        {
            database = new Database();
            HttpContext.Current.Items[key] = database;
        }
    }

    private static void OnEndRequest(object sender, EventArgs e)
    {
        var database = HttpContext.Current.Items[key] as Database;

        if (database != null)
        {
            database.SaveChanges();
            database.Dispose();
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, add the &lt;code&gt;Telerik.Web.Mvc.dll&lt;/code&gt; from the binary folder that you have downloaded previously.&lt;/p&gt;

&lt;p&gt;Once you include the dll, the first thing you should do is register the &lt;code&gt;HttpHandler&lt;/code&gt; for the Web Assets, lets put these lines in the &lt;code&gt;web.config&lt;/code&gt; file (I am only showing the relevant section of the &lt;code&gt;web.config&lt;/code&gt;):&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:94e4eb05-67b3-4324-a3b9-b8fc97888411" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;?xml version="1.0"?&amp;gt;
&amp;lt;configuration&amp;gt;
    &amp;lt;system.web&amp;gt;
        &amp;lt;httpHandlers&amp;gt;
            &amp;lt;add verb="GET,HEAD" path="asset.axd" validate="false" type="Telerik.Web.Mvc.WebAssetHttpHandler, Telerik.Web.Mvc" /&amp;gt;
        &amp;lt;/httpHandlers&amp;gt;
    &amp;lt;/system.web&amp;gt;
    &amp;lt;system.webServer&amp;gt;
        &amp;lt;handlers&amp;gt;
            &amp;lt;remove name="AssetHandler" /&amp;gt;
            &amp;lt;add name="AssetHandler" preCondition="integratedMode" verb="GET,HEAD" path="asset.axd" type="Telerik.Web.Mvc.WebAssetHttpHandler, Telerik.Web.Mvc" /&amp;gt;
        &amp;lt;/handlers&amp;gt;
    &amp;lt;/system.webServer&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, Copy the &lt;code&gt;telerik.common.min.css&lt;/code&gt;, &lt;code&gt;telerik.vista.min.css&lt;/code&gt; and &lt;code&gt;Vista&lt;/code&gt; from the download Content folder to your project Content folder. We also have to copy few javascripts files, please copy the &lt;code&gt;telerik.common.min.js&lt;/code&gt;, &lt;code&gt;telerik.grid.min.js&lt;/code&gt; and &lt;code&gt;telerik.grid.filtering.min.js&lt;/code&gt; from the downloaded Scripts folder to your project Scripts folder. Once you are done, it will look very similar to the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/SE_59B2EC01.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SE" border="0" alt="SE" src="http://weblogs.asp.net/blogs/rashid/SE_thumb_38AB3F8E.png" width="464" height="601" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Now open the &lt;code&gt;Site.Master&lt;/code&gt; from Views/Shared directory and put the following lines in the head section:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:b3fa32c3-de1f-46d7-974f-f47dfc42e280" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;head runat="server"&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;asp:ContentPlaceHolder ID="TitleContent" runat="server" /&amp;gt;&amp;lt;/title&amp;gt;
    &amp;lt;%= Html.Telerik().StyleSheetRegistrar()
                      .DefaultGroup(group =&amp;gt; group.Add("Site.css")
                                                  .Add("telerik.common.css")
                                                  .Add("telerik.vista.css")
                                                  .Combined(true)
                                   ) %&amp;gt;
&amp;lt;/head&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will ensure the stylesheets files that we have added in the previous steps will be included when the page renders. We have do the same for javascript files, but this time we will only add a ScriptRegistrar at the bottom of the page, but we will not add the javascript files like we did for the stylesheet files. Lets put the following code at the bottom of the page:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:3d34711b-b275-4aa0-875c-f07c5bbf4cfe" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;    &amp;lt;% Html.Telerik().ScriptRegistrar()
                     .DefaultGroup(group =&amp;gt; group.Combined(true).Compress(true))
                     .Render(); %&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, go back to the &lt;code&gt;Index&lt;/code&gt; method of the &lt;code&gt;CustomerController&lt;/code&gt;, right click and select Add View, this will show the Add View Dialog. When the dialog appears, turn on the strongly typed view and select the &lt;code&gt;Customers&lt;/code&gt; class as the view data class and finally select the List in View content drop down.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/AV_7E2019EC.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="AV" border="0" alt="AV" src="http://weblogs.asp.net/blogs/rashid/AV_thumb_0BBDDA82.png" width="470" height="574" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Once the view is generated replace the generated code with the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:931445cf-f339-4ba7-9531-91c115008e3d" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.Telerik()
       .Grid(Model)
       .Name("customers")
       .PrefixUrlParameters(false)
       .Columns(columns =&amp;gt;
                {
                    columns.Add(c =&amp;gt;
                                {
                                    %&amp;gt;
                                        &amp;lt;%= Html.ActionLink("Edit", "Edit", new { id = c.CustomerID })%&amp;gt;
                                        &amp;lt;%= Html.ActionLink("Delete", "Delete", new { id = c.CustomerID })%&amp;gt;
                                    &amp;lt;%
                                }).Title("Action");

                    columns.Add(c =&amp;gt; c.CompanyName).Width(200);
                    columns.Add(c =&amp;gt; c.ContactName);
                    columns.Add(c =&amp;gt; c.Address);
                    columns.Add(c =&amp;gt; c.City);
                    columns.Add(c =&amp;gt; c.PostalCode);
                    columns.Add(c =&amp;gt; c.Country);
                    columns.Add(c =&amp;gt; c.Phone);
                    columns.Add(c =&amp;gt; c.Fax);
                })
        .Filterable()
        .Sortable(sort =&amp;gt; sort.SortMode(GridSortMode.MultipleColumn))
        .Pageable()
        .Scrollable(scrolling =&amp;gt; scrolling.Height(250))
        .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now press F5 and navigate to /Customers, you will find a nice looking Grid like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/GRID_2AA0602E.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="GRID" border="0" alt="GRID" src="http://weblogs.asp.net/blogs/rashid/GRID_thumb_0B59A55C.png" width="1388" height="407" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As you can see the Grid has out of the box support for data sorting/filtering/paging, all you have to do is set an &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; as its &lt;code&gt;DataSource&lt;/code&gt;, the rest is taken care by itself. If the &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; has a Linq Provider the data will be processed at the database level. If you run the SQL Profiler for the above example and navigate to page 2 you will find the following SQL is generated:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:cc86a72b-4e99-4303-aa33-24447293cd8f" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;SELECT TOP (10) 
[Project1].[CustomerID] AS [CustomerID], 
[Project1].[CompanyName] AS [CompanyName], 
[Project1].[ContactName] AS [ContactName], 
[Project1].[ContactTitle] AS [ContactTitle], 
[Project1].[Address] AS [Address], 
[Project1].[City] AS [City], 
[Project1].[Region] AS [Region], 
[Project1].[PostalCode] AS [PostalCode], 
[Project1].[Country] AS [Country], 
[Project1].[Phone] AS [Phone], 
[Project1].[Fax] AS [Fax]
FROM ( SELECT [Project1].[C1] AS [C1], [Project1].[CustomerID] AS [CustomerID], [Project1].[CompanyName] AS [CompanyName], [Project1].[ContactName] AS [ContactName], [Project1].[ContactTitle] AS [ContactTitle], [Project1].[Address] AS [Address], [Project1].[City] AS [City], [Project1].[Region] AS [Region], [Project1].[PostalCode] AS [PostalCode], [Project1].[Country] AS [Country], [Project1].[Phone] AS [Phone], [Project1].[Fax] AS [Fax], row_number() OVER (ORDER BY [Project1].[C1] ASC) AS [row_number]
	FROM ( SELECT 
		CASE WHEN ([Extent1].[CustomerID] IS NOT NULL) THEN [Extent1].[CustomerID] END AS [C1], 
		[Extent1].[CustomerID] AS [CustomerID], 
		[Extent1].[CompanyName] AS [CompanyName], 
		[Extent1].[ContactName] AS [ContactName], 
		[Extent1].[ContactTitle] AS [ContactTitle], 
		[Extent1].[Address] AS [Address], 
		[Extent1].[City] AS [City], 
		[Extent1].[Region] AS [Region], 
		[Extent1].[PostalCode] AS [PostalCode], 
		[Extent1].[Country] AS [Country], 
		[Extent1].[Phone] AS [Phone], 
		[Extent1].[Fax] AS [Fax]
		FROM [dbo].[Customers] AS [Extent1]
	)  AS [Project1]
)  AS [Project1]
WHERE [Project1].[row_number] &amp;gt; 10
ORDER BY [Project1].[C1] ASC&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The rest of the screens are pretty simple, just use the ASP.NET MVC Add View dialog to implement them and that is it for the Entity Framework and Web form view engine.&lt;/p&gt;

&lt;p&gt;Now, lets do the same for NHibernate and Spark.&lt;/p&gt;

&lt;p&gt;First, Create a new ASP.NET MVC Project named AltNorthwind and skip the Unit Test Project. Now, the add following the references:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;NHibernate &lt;/li&gt;

  &lt;li&gt;NHibernate.Linq &lt;/li&gt;

  &lt;li&gt;FluentNHibernate &lt;/li&gt;

  &lt;li&gt;Spark. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, right click the Models folder add a new class named &lt;code&gt;Customers&lt;/code&gt; and create simple getter/setter properties for the Customers table fields, also ensure the properties are declared as &lt;code&gt;virtual&lt;/code&gt;.Next, Add a new class named &lt;code&gt;CustomerMap&lt;/code&gt; which will be used by the NHibernate to map the Customers class with the Customer table.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:090eb41e-112c-47ed-ba8d-8469f435352c" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class CustomerMap : ClassMap&amp;lt;Customers&amp;gt;
{
    public CustomerMap()
    {
        Id(c =&amp;gt; c.CustomerID).Length(5).Not.Nullable();
        Map(c =&amp;gt; c.CompanyName).Length(40).Not.Nullable();
        Map(c =&amp;gt; c.ContactName).Length(30);
        Map(c =&amp;gt; c.ContactTitle).Length(30);
        Map(c =&amp;gt; c.Address).Length(60);
        Map(c =&amp;gt; c.City).Length(15);
        Map(c =&amp;gt; c.Region).Length(15);
        Map(c =&amp;gt; c.PostalCode).Length(10);
        Map(c =&amp;gt; c.Country).Length(15);
        Map(c =&amp;gt; c.Phone).Length(24);
        Map(c =&amp;gt; c.Fax).Length(24);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Lets create the &lt;code&gt;Repository&lt;/code&gt;, we will be using the same &lt;code&gt;IRepository&lt;/code&gt; interface that we used in the Entity Framework section.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:ed0b4775-b1cc-48e8-bb36-b38d0161977f" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class Repository&amp;lt;TEntity, TId&amp;gt; : IRepository&amp;lt;TEntity, TId&amp;gt;
{
    private readonly ISession session;

    public Repository() : this(NHibernateSessionPerRequest.CurrentSession)
    {
    }

    public Repository(ISession session)
    {
        this.session = session;
    }

    public void Add(TEntity entity)
    {
        session.SaveOrUpdate(entity);
    }

    public void Delete(TId id)
    {
        session.Delete(Get(id));
    }

    public TEntity Get(TId id)
    {
        return session.Get&amp;lt;TEntity&amp;gt;(id);
    }

    public IEnumerable&amp;lt;TEntity&amp;gt; All()
    {
        return session.Linq&amp;lt;TEntity&amp;gt;();
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;As we can see that we are using the NHibernate &lt;code&gt;ISession&lt;/code&gt; which is passed in the constructor similar to the Entity Framework version, we are also using an HttpModule for managing NHibernate session.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:82c04956-f391-486b-a6d4-8acb1a98316f" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class NHibernateSessionPerRequest : IHttpModule
{
    private static readonly ISessionFactory sessionFactory = CreateSessionFactory();

    public static ISession CurrentSession
    {
        get
        {
            return sessionFactory.GetCurrentSession();
        }
    }

    public void Init(HttpApplication context)
    {
        context.BeginRequest += OnBeginRequest;
        context.EndRequest += OnEndRequest;
    }

    public void Dispose()
    {
    }

    private static void OnBeginRequest(object sender, EventArgs e)
    {
        var session = sessionFactory.OpenSession();

        session.BeginTransaction();

        CurrentSessionContext.Bind(session);
    }

    private static void OnEndRequest(object sender, EventArgs e)
    {
        var session = CurrentSessionContext.Unbind(sessionFactory);

        if (session != null)
        {
            try
            {
                session.Transaction.Commit();
            }
            catch
            {
                session.Transaction.Rollback();
            }
            finally
            {
                session.Close();
                session.Dispose();
            }
        }
    }

    private static ISessionFactory CreateSessionFactory()
    {
        const string ConnectionStringName = "NorthwindConnectionString";

        var configuration = Fluently.Configure()
                                    .Database(MsSqlConfiguration.MsSql2005.ConnectionString(x =&amp;gt; x.FromConnectionStringWithKey(ConnectionStringName)))
                                    .ExposeConfiguration(c =&amp;gt; c.SetProperty("current_session_context_class", "web"))
                                    .Mappings(m =&amp;gt; m.FluentMappings.AddFromAssemblyOf&amp;lt;NHibernateSessionPerRequest&amp;gt;());

        return configuration.BuildSessionFactory();
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Controller&lt;/code&gt; is same as the Entity Framework version. Now, lets configure the Spark view engine, first put the following lines in the &lt;code&gt;web.config&lt;/code&gt; file.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:bbe63b10-b7ab-4272-946f-1f2ddd51ecf8" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;configSections&amp;gt;
    &amp;lt;section name="spark" type="Spark.Configuration.SparkSectionHandler, Spark"/&amp;gt;
&amp;lt;/configSections&amp;gt;
&amp;lt;spark&amp;gt;
    &amp;lt;compilation debug="true"&amp;gt;
        &amp;lt;assemblies&amp;gt;
            &amp;lt;add assembly="AltNorthwind"/&amp;gt;
            &amp;lt;add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/&amp;gt;
        &amp;lt;/assemblies&amp;gt;
    &amp;lt;/compilation&amp;gt;
    &amp;lt;pages automaticEncoding="true"&amp;gt;
        &amp;lt;namespaces&amp;gt;
            &amp;lt;add namespace="System.Collections.Generic"/&amp;gt;
            &amp;lt;add namespace="System.Linq"/&amp;gt;
            &amp;lt;add namespace="System.Web.Mvc"/&amp;gt;
            &amp;lt;add namespace="System.Web.Mvc.Html"/&amp;gt;
            &amp;lt;add namespace="System.Web.Routing"/&amp;gt;
            &amp;lt;add namespace="Telerik.Web.Mvc.UI"/&amp;gt;
        &amp;lt;/namespaces&amp;gt;
    &amp;lt;/pages&amp;gt;
&amp;lt;/spark&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And register the view engine in the &lt;code&gt;global.asax&lt;/code&gt;, like the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9991a947-25de-4344-8a45-20608cd51c2a" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    SparkEngineStarter.RegisterViewEngine();
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, Copy the &lt;code&gt;telerik.common.min.css&lt;/code&gt;, &lt;code&gt;telerik.vista.min.css&lt;/code&gt; and &lt;code&gt;Vista&lt;/code&gt; from the download Content folder to your project Content folder and&amp;#160; &lt;code&gt;telerik.common.min.js&lt;/code&gt;, &lt;code&gt;telerik.grid.min.js&lt;/code&gt; and &lt;code&gt;telerik.grid.filtering.min.js&lt;/code&gt; from the downloaded Scripts folder to your project Scripts folder, same as we did in the Entity Framework version.&lt;/p&gt;

&lt;p&gt;Now, lets add an &lt;code&gt;application.spark&lt;/code&gt; file in Views/Shared for the stylesheets and javascripts and add the following code in the head section for the stylesheets registration:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:85e71dba-4df7-4b74-a55e-c95205cbd2ab" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.Telerik().StyleSheetRegistrar()
                  .DefaultGroup(group =&amp;gt; group.Add("Site.css")
                                              .Add("telerik.common.css")
                                              .Add("telerik.vista.css")
                                              .Combined(true)
                               ) 
                   .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And at the bottom for the javascript files:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:59a60bb8-1e17-4db1-b101-48a2732deb0b" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.Telerik().ScriptRegistrar()
                 .DefaultGroup(group =&amp;gt; group.Combined(true).Compress(true))
                 .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, create a new folder named Customer under the Views folder and add new spark file named &lt;code&gt;Index.spark&lt;/code&gt; and put the following code:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:23f76682-f1f7-44b4-8782-af8d0b247a69" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;content name="TitleContent"&amp;gt;
    Customers
&amp;lt;/content&amp;gt;
&amp;lt;content name="MainContent"&amp;gt;
    &amp;lt;h2&amp;gt;Customers&amp;lt;/h2&amp;gt;
    &amp;lt;viewdata model="IEnumerable[[Customers]]"/&amp;gt;
    &amp;lt;% Html.Telerik()
           .Grid(Model)
           .Name("customers")
           .PrefixUrlParameters(false)
           .Columns(columns =&amp;gt;
                    {
                        columns.Add(c =&amp;gt;
                                    {
                                        %&amp;gt;
                                            !{ Html.ActionLink("Edit", "Edit", new { id = c.CustomerID })}
                                            !{ Html.ActionLink("Delete", "Delete", new { id = c.CustomerID })}
                                        &amp;lt;%
                                    }).Title("Action");

                        columns.Add(c =&amp;gt; c.CompanyName).Width(200);
                        columns.Add(c =&amp;gt; c.ContactName);
                        columns.Add(c =&amp;gt; c.Address);
                        columns.Add(c =&amp;gt; c.City);
                        columns.Add(c =&amp;gt; c.PostalCode);
                        columns.Add(c =&amp;gt; c.Country);
                        columns.Add(c =&amp;gt; c.Phone);
                        columns.Add(c =&amp;gt; c.Fax);
                    })
            .Sortable(sort =&amp;gt; sort.SortMode(GridSortMode.MultipleColumn))
            .Pageable()
            .Scrollable(scrolling =&amp;gt; scrolling.Height(250))
            .Render(); %&amp;gt;
    &amp;lt;p&amp;gt;!{ Html.ActionLink("Create New", "Create") }&amp;lt;/p&amp;gt;
&amp;lt;/content&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once you are done, press F5 and navigate to /Customer, you will find a nice looking Grid. I am skipping the rest of the views as they are pretty easy to implement, but you will find the complete code in the following link.&lt;/p&gt;

&lt;p&gt;That’s it for today, I hope I will be posting more on these components, so stay tuned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source Codes:&lt;/strong&gt; &lt;a href="http://cid-11b76f34c007bb9f.skydrive.live.com/self.aspx/.Documents/TelerikMVCGridCRudDemo.zip" target="_blank"&gt;TelerikMVCGridCRUDDemo.zip&lt;/a&gt; (&lt;strong&gt;Sorry for the earlier inconvenience, just made it public, it is accessible now.&lt;/strong&gt;)&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f11%2f05%2fusing-telerik-mvc-grid-in-crud-scenario.aspx&amp;amp;title=Using+Telerik+MVC+Grid+in+CRUD+Scenario"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/11/05/using-telerik-mvc-grid-in-crud-scenario.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7247727" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/a_Qi51PcovQ" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Telerik/default.aspx">Telerik</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Grid/default.aspx">Grid</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/11/05/using-telerik-mvc-grid-in-crud-scenario.aspx</feedburner:origLink></item><item><title>Telerik ASP.NET MVC Grid Preview (Take 1)</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/bAEPaYZZLek/telerik-asp-net-mvc-grid-preview-take-1.aspx</link><pubDate>Wed, 16 Sep 2009 16:06:26 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7208258</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>15</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7208258</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7208258</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/09/16/telerik-asp-net-mvc-grid-preview-take-1.aspx#comments</comments><description>&lt;p&gt;Those who have seen my &lt;a href="http://twitter.com/ManzurRashid/status/3930541348" target="_blank"&gt;tweet&lt;/a&gt;, already know that we have started working on our ASP.NET MVC Grid. In post I will show you the very early version of our Grid, so that you can provide your valuable feedback to guide us in the right direction. So far, we have implemented the paging and multi-column sorting. Let me show you the minimum code to set it up.&lt;/p&gt;  &lt;p&gt;First, we will create an action method which creates some random data for view:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:eae337c9-231e-4b2d-b19a-f44131ee786c" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public ActionResult Basic()
{
    Random rnd = new Random();

    IList&amp;lt;InMemoryCustomer&amp;gt; model = new List&amp;lt;InMemoryCustomer&amp;gt;();

    for (int i = 1; i &amp;lt;= 100; i++)
    {
        InMemoryCustomer c = new InMemoryCustomer
                                 {
                                     Id = rnd.Next(1, 1000),
                                     Name = string.Format("Dummy Name #{0}", i),
                                     Address = string.Format("Dummy Address #{0}", i),
                                     RegisterAt = DateTime.Now.AddMonths(-rnd.Next(1, 48)).AddDays(-rnd.Next(0, 365)),
                                     Balance = rnd.Next(1000, 10000),
                                     IsActive = ((i % 4) == 0)
                                 };

        model.Add(c);
    }

    return View(model);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, in the view:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:a79b5875-ebcb-425d-a7b3-c98dc2e1a61b" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage&amp;lt;IEnumerable&amp;lt;InMemoryCustomer&amp;gt;&amp;gt;" %&amp;gt;
&amp;lt;asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"&amp;gt;
    In Memory
&amp;lt;/asp:Content&amp;gt;
&amp;lt;asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"&amp;gt;
    &amp;lt;h2&amp;gt;Basic&amp;lt;/h2&amp;gt;
    &amp;lt;% Html.Telerik().Grid&amp;lt;InMemoryCustomer&amp;gt;()
           .Name("MyGrid")
           .Columns(
                        columns =&amp;gt;
                        {
                            columns.Add(c =&amp;gt; c.Id);
                            columns.Add(c =&amp;gt; c.Name);
                            columns.Add(c =&amp;gt; c.Address);
                            columns.Add(c =&amp;gt; c.RegisterAt).Format("{0:MM/dd/yyyy}");
                            columns.Add(c =&amp;gt; c.IsActive).HeaderText("Active");
                        }
                   )
           .SortMode(GridSortMode.MultiColumn)
           .Pager(pager =&amp;gt; pager.PageSize(10).Style(GridPagerStyle.FirstPreviousNextLast))
           .BindTo(Model)
           .Render(); %&amp;gt;
&amp;lt;/asp:Content&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When you run the above, it will show you a nice looking grid like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/Basic_3F5E65B7.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Basic" border="0" alt="Basic" src="http://weblogs.asp.net/blogs/rashid/Basic_thumb_65909942.png" width="1333" height="295" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Check that when defining the columns, we are using strongly typed syntax which means you will get the complete benefit of compile time checking, also note that we have set the &lt;code&gt;SortMode&lt;/code&gt; to &lt;code&gt;MultiColumn&lt;/code&gt;, other values are &lt;code&gt;SingleColumn&lt;/code&gt; and &lt;code&gt;None&lt;/code&gt;. When you click any of the column headers or the links in the pager, it will append the order by and page number in the query string like the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;?MyGrid-orderBy=Name asc%2CAddress desc&amp;amp;MyGrid-page=2&lt;/code&gt; // Order By Name Ascending, Address Descending and Page is 2&lt;/p&gt;

&lt;p&gt;&lt;code&gt;?MyGrid-orderBy=Name asc%2CRegisterAt asc&lt;/code&gt; //Order By Name Ascending, RegisterAt Ascending and Page is 1 that why it is not added&lt;/p&gt;

&lt;p&gt;As you can see, we are also using the Grid Name as prefix for the query string parameters, this is required to identify the parameter when there are more than one grid in a view. You can easily turn it off my using the &lt;code&gt;IncludeNameInParameterAsPrefix&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; when you have only one Grid in a view. Lets take a another quick look how to turn off the Name prefix:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6e8e5c71-c588-411d-8727-f2befe870fc8" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;&amp;lt;% Html.Telerik().Grid&amp;lt;InMemoryCustomer&amp;gt;()
       .Name("MyGrid")
       .Columns(
                    columns =&amp;gt;
                    {
                        columns.Add(c =&amp;gt; c.Id);
                        columns.Add(c =&amp;gt; c.Name);
                        columns.Add(c =&amp;gt; c.Address);
                        columns.Add(c =&amp;gt; c.RegisterAt).Format("{0:MM/dd/yyyy}");
                        columns.Add(c =&amp;gt; c.IsActive).HeaderText("Active");
                    }
               )
       .SortMode(GridSortMode.MultiColumn)
       .IncludeNameInParameterAsPrefix(false)
       .Pager(pager =&amp;gt; pager.PageSize(10).Style(GridPagerStyle.FirstPreviousNextLast))
       .BindTo(Model)
       .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;(Check the line number 14 in the above snippet) Now, when you run the above code and click few of the column headers, it will get a similar picture like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/PreSorted_584A102F.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="PreSorted" border="0" alt="PreSorted" src="http://weblogs.asp.net/blogs/rashid/PreSorted_thumb_0824B1F1.png" width="1331" height="290" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Now, you will see the urls are generated without the grid name prefix:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;?orderBy=Name desc%2CRegisterAt asc&amp;amp;page=2&lt;/code&gt; // Order By Name Descending, RegisterAt Ascending and Page 2&lt;/p&gt;

&lt;p&gt;&lt;code&gt;?orderBy=Address%20asc&lt;/code&gt; // Order by Address Ascending and Page 1 &lt;/p&gt;

&lt;p&gt;So far, we are using the Query String, What the about the routing? yes you can also use the routing instead of the old and ugly query string, but to use Routing you have define the route first, this is the reason, I have shown the query string examples first. Now, let me show you the routing example:&lt;/p&gt;

&lt;p&gt;First we will define a route in &lt;code&gt;global.asax&lt;/code&gt; like the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:1ca138ab-1642-47ef-bd37-38e98fe8b142" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;routes.MapRoute("PrettyUrl", "{controller}/PrettyUrl/{orderBy}/{page}", new { controller = "Grid", action = "PrettyUrl", orderBy = string.Empty, page = 1 });&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, we will create an action method very similar to the above query string example, except, it now accepts the orderBy and page as argument:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:65f57ca3-eaec-45f4-9175-80500e063e3d" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public ActionResult PrettyUrl(string orderBy, int? page)
{
    Random rnd = new Random();

    IList&amp;lt;InMemoryCustomer&amp;gt; model = new List&amp;lt;InMemoryCustomer&amp;gt;();

    for (int i = 1; i &amp;lt;= 100; i++)
    {
        InMemoryCustomer c = new InMemoryCustomer
                                 {
                                     Id = rnd.Next(1, 1000),
                                     Name = string.Format("Dummy Name #{0}", i),
                                     Address = string.Format("Dummy Address #{0}", i),
                                     RegisterAt =
                                         DateTime.Now.AddMonths(-rnd.Next(1, 48)).AddDays(-rnd.Next(0, 365)),
                                     Balance = rnd.Next(1000, 10000),
                                     IsActive = ((i%4) == 0)
                                 };

        model.Add(c);
    }

    return View(model);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And the view is exactly same as above:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:87264ffa-e8b2-4e2f-b031-5330fb3bfda1" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;&amp;lt;% Html.Telerik().Grid&amp;lt;InMemoryCustomer&amp;gt;()
       .Name("MyGrid")
       .Columns(
                    columns =&amp;gt;
                    {
                        columns.Add(c =&amp;gt; c.Id);
                        columns.Add(c =&amp;gt; c.Name);
                        columns.Add(c =&amp;gt; c.Address);
                        columns.Add(c =&amp;gt; c.RegisterAt).Format("{0:MM/dd/yyyy}");
                        columns.Add(c =&amp;gt; c.IsActive).HeaderText("Active");
                    }
               )
       .SortMode(GridSortMode.MultiColumn)
       .IncludeNameInParameterAsPrefix(false)
       .Pager(pager =&amp;gt; pager.PageSize(10).Style(GridPagerStyle.FirstPreviousNextLast))
       .BindTo(Model)
       .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now when run it, the urls will appear like the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/Grid/PrettyUrl/Name asc,Address asc,RegisterAt asc/2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/Grid/PrettyUrl/Name desc,IsActive asc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;IE will replace the spaces with Url encoded %20, If you have used the ADO.NET Data Service you already guess that we are following the same style for formatting order by clause as ADO.NET Data Service. The default value for &lt;code&gt;orderBy&lt;/code&gt; and &lt;code&gt;page&lt;/code&gt; parameters are same as there names, if your route is declared with some other names or you want to change the values for query string, use the following syntax (Check line 14 and 15):&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:8980cfcb-a9cc-429f-abc8-a389797dc27f" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.Telerik().Grid&amp;lt;InMemoryCustomer&amp;gt;()
       .Name("MyGrid")
       .Columns(
                    columns =&amp;gt;
                    {
                        columns.Add(c =&amp;gt; c.Id);
                        columns.Add(c =&amp;gt; c.Name);
                        columns.Add(c =&amp;gt; c.Address);
                        columns.Add(c =&amp;gt; c.RegisterAt).Format("{0:MM/dd/yyyy}");
                        columns.Add(c =&amp;gt; c.IsActive).HeaderText("Active");
                    }
               )
       .SortMode(GridSortMode.MultiColumn)
       .OrderByParameterName("sortBy")
       .CurrentPageParameterName("p")
       .Pager(pager =&amp;gt; pager.PageSize(10).Style(GridPagerStyle.FirstPreviousNextLast))
       .BindTo(Model)
       .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Currently, the routing only works for single grid due to the limitation of the ASP.NET Routing, I will post more on this later on.&lt;/p&gt;

&lt;p&gt;Before concluding the post, there are one more nice feature that I like to mention, if you are wondering how the above code is doing the auto paging and sorting, let me tell you that we are using the same DataEngine as our Wpf Control suite is using, the nice things about it that it has the complete support to propagate the arbitrary expressions to query providers, which means if you are using LinqToSQL, LinqToEntities, LinqToNHibernate or any database Linq provider then the actual processing will be done by database server rather than in memory operation. But, if want to take charges of this operations, you can certainly do it, just set the &lt;code&gt;RequireProcessing&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;This is a just the start, there are lot more features we will be adding before our final release, We will be posting the features as we develop to gather feedback from you, so please let us know what you like, what you do not like and how we can improve.&lt;/p&gt;

&lt;p&gt;Thanks.&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f09%2f16%2ftelerik-asp-net-mvc-grid-preview-take-1.aspx&amp;amp;title=Telerik+ASP.NET+MVC+Grid+Preview+(Take+1)"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/09/16/telerik-asp-net-mvc-grid-preview-take-1.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7208258" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/bAEPaYZZLek" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Telerik/default.aspx">Telerik</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/09/16/telerik-asp-net-mvc-grid-preview-take-1.aspx</feedburner:origLink></item><item><title>Shrinkr - Url Shrinking Service Developed with Entity Framework 4.0, Unity, ASP.NET MVC And jQuery (Part 3)</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/iEPH3MhImgk/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-3.aspx</link><pubDate>Tue, 15 Sep 2009 09:57:54 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7206212</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>7</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7206212</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7206212</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/09/15/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-3.aspx#comments</comments><description>&lt;p&gt;In the &lt;a href="http://weblogs.asp.net/rashid/archive/2009/09/13/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-2.aspx" target="_blank"&gt;previous post&lt;/a&gt;, we have created our initial repositories, in this post I will show how you can use the compiled query of Entity Framework in our repository. To use the compiled query we will put each query of our repositories into its own class and create some common interfaces that we can use in our repositories.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;IQuery&lt;/strong&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:31954a0b-f65b-4611-aa91-ec26f8b674fd" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    public interface IQuery&amp;lt;TResult&amp;gt;
    {
        TResult Execute(Database database);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;IQueryFactory&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:100fd884-478b-4eb1-b0f5-d7ee5255d3c8" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    using System.Collections.Generic;

    public interface IQueryFactory
    {
        bool UseCompiled
        {
            get;
        }

        IQuery&amp;lt;User&amp;gt; CreateUserById(long userId);

        IQuery&amp;lt;User&amp;gt; CreateUserByName(string userName);

        IQuery&amp;lt;User&amp;gt; CreateUserByApiKey(string apiKey);

        IQuery&amp;lt;ShortUrl&amp;gt; CreateShortUrlById(long shortUrlId);

        IQuery&amp;lt;ShortUrl&amp;gt; CreateShortUrlByHash(string urlHash);

        IQuery&amp;lt;ShortUrl&amp;gt; CreateShortUrlByAlias(string alias);

        IQuery&amp;lt;int&amp;gt; CreateShortUrlCountByUserId(long userId);

        IQuery&amp;lt;IEnumerable&amp;lt;ShortUrl&amp;gt;&amp;gt; CreateShortUrlsByUserId(long userId, int start, int max);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we will modify our &lt;code&gt;RepositoryBase&lt;/code&gt;, so that we can pass the &lt;code&gt;IQuaryFactory&lt;/code&gt; in its constructor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RepositoryBase&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:337458c8-e1b9-4827-9c69-9d3f6209d36a" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    public abstract class RepositoryBase&amp;lt;TEntity&amp;gt; where TEntity : class, IEntity
    {
        protected RepositoryBase(Database database, IQueryFactory queryFactory)
        {
            Check.Argument.IsNotNull(database, "database");
            Check.Argument.IsNotNull(queryFactory, "queryFactory");

            Database = database;
            QueryFactory = queryFactory;
        }

        protected Database Database
        {
            get;
            private set;
        }

        protected IQueryFactory QueryFactory
        {
            get;
            private set;
        }

        public virtual void Add(TEntity entity)
        {
            Check.Argument.IsNotNull(entity, "entity");

            Database.ObjectSet&amp;lt;TEntity&amp;gt;().AddObject(entity);
        }

        public virtual void Delete(TEntity entity)
        {
            Check.Argument.IsNotNull(entity, "entity");

            Database.ObjectSet&amp;lt;TEntity&amp;gt;().DeleteObject(entity);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can now use the query factory in our repository, for example, in &lt;code&gt;UserRepository&lt;/code&gt; we will be able to use:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:ec83a2ed-e0af-4cb7-aba4-bcd5fd8c5897" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public User GetById(long id)
{
    IQuery&amp;lt;User&amp;gt; query = QueryFactory.CreateUserById(id);

    return query.Execute(Database);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, lets check how the query is constructed, first the base class which implements the &lt;code&gt;IQuery&amp;lt;T&amp;gt;&lt;/code&gt; interface:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;QueryBase&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d3a7c757-08b1-4f57-917d-7c1e1192d0b8" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    public abstract class QueryBase&amp;lt;TResult&amp;gt; : IQuery&amp;lt;TResult&amp;gt;
    {
        protected QueryBase(bool useCompiled)
        {
            UseCompiled = useCompiled;
        }

        protected bool UseCompiled
        {
            get;
            private set;
        }

        public abstract TResult Execute(Database database);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;as mentioned that each query will have its own class, for example, for the above user by id query, we will have the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:dd07f0ea-74d5-471d-9165-4d9be0e87489" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    using System;
    using System.Data.Objects;
    using System.Linq;
    using System.Linq.Expressions;

    public class UserByIdQuery : QueryBase&amp;lt;User&amp;gt;
    {
        private static readonly Expression&amp;lt;Func&amp;lt;Database, long, User&amp;gt;&amp;gt; expression = (Database database, long id) =&amp;gt; database.Users.SingleOrDefault(user =&amp;gt; user.Id == id);
        private static readonly Func&amp;lt;Database, long, User&amp;gt; plainQuery = expression.Compile();
        private static readonly Func&amp;lt;Database, long, User&amp;gt; compiledQuery = CompiledQuery.Compile(expression);

        private readonly long userId;

        public UserByIdQuery(bool useCompiled, long userId) : base(useCompiled)
        {
            Check.Argument.IsNotNegative(userId, "userId");

            this.userId = userId;
        }

        public override User Execute(Database database)
        {
            Check.Argument.IsNotNull(database, "database");

            return UseCompiled ?
                   compiledQuery(database, userId) :
                   plainQuery(database, userId);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and the implementation of &lt;code&gt;QueryFactory&lt;/code&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:70cfe87e-fc6f-46e1-be94-e50ff58a53e0" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    using System.Collections.Generic;

    public class QueryFactory : IQueryFactory
    {
        public QueryFactory(bool useCompiled)
        {
            UseCompiled = useCompiled;
        }

        public bool UseCompiled
        {
            get;
            private set;
        }

        public IQuery&amp;lt;User&amp;gt; CreateUserById(long userId)
        {
            return new UserByIdQuery(UseCompiled, userId);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Now, when unit testing the Repositories we will be using the plain queries, for example the &lt;code&gt;UserRepository&lt;/code&gt; will be constructed like the following in unit tests:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d2ebb2d3-e33c-48e9-b224-bc3386166a61" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public UserRepositoryTests()
{
    database = new Mock&amp;lt;Database&amp;gt;(configurationManager.Object, "Dummy");
    var queryFactory = new QueryFactory(false); // plain query

    repository = new UserRepository(database.Object, queryFactory);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and that’s it. But for the data access layer, I would highly recommend to&amp;#160; have the integration tests as well. The reasons are:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It will ensure the underlying Linq Providers does support the Linq queries that we have in your repositories, although the Linq queries we have written here are very simple. &lt;/li&gt;

  &lt;li&gt;By using the SQL Profiler we can ensure the generated SQLs are really optimized. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But to start writing the integration tests, we have one more important thing to do, the &lt;code&gt;UnitOfWork&lt;/code&gt;, which persist the changes in our database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UnitOfWork&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:4fcebc1c-2df8-41dc-b0bd-d1ce2816b2b4" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    public class UnitOfWork : IUnitOfWork
    {
        private readonly Database database;

        public UnitOfWork(Database database)
        {
            Check.Argument.IsNotNull(database, "database");

            this.database = database;
        }

        public void Commit()
        {
            database.Commit();
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, lets write our first integration test:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:49d39534-2763-4f3b-806d-e60ab021bfdc" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.IntegrationTests
{
    using System;

    using Xunit;
    using Xunit.Extensions;

    using IoC = global::Microsoft.Practices.ServiceLocation.ServiceLocator;

    public class UserRepositoryTests : TestBase
    {
        private const string Name = "http://kazimanzurrashid.myopenid.com";

        private readonly IUnitOfWork unitOfWork;
        private readonly IUserRepository repository;

        public UserRepositoryTests()
        {
            unitOfWork = IoC.Current.GetInstance&amp;lt;IUnitOfWork&amp;gt;();
            repository = IoC.Current.GetInstance&amp;lt;IUserRepository&amp;gt;();
        }

        [Fact, AutoRollback]
        public void Should_be_able_to_add_user()
        {
            var user = CreateUser();

            Assert.NotEqual(0, user.Id);
        }

        [Fact, AutoRollback]
        public void Should_be_able_to_update_user()
        {
            var user = CreateUser();

            user.Email = "kazimanzurrashid@gmail.com";

            unitOfWork.Commit();

            var updatedUser = repository.GetById(user.Id);

            Assert.Equal("kazimanzurrashid@gmail.com", updatedUser.Email);
        }

        [Fact, AutoRollback]
        public void Should_be_able_to_delete_user()
        {
            var userId = CreateUser().Id;
            var user = repository.GetById(userId);

            repository.Delete(user);
            unitOfWork.Commit();

            user = repository.GetById(userId);

            Assert.Null(user);
        }

        [Fact, AutoRollback]
        public void Should_be_able_to_get_user_by_id()
        {
            var userId = CreateUser().Id;
            var user = repository.GetById(userId);

            Assert.NotNull(user);
        }

        [Fact, AutoRollback]
        public void Should_be_able_to_get_user_by_name()
        {
            CreateUser();

            var user = repository.GetByName(Name);

            Assert.NotNull(user);
        }

        [Fact, AutoRollback]
        public void Should_be_able_to_get_user_by_api_key()
        {
            var apiKey = CreateUser().ApiSetting.Key;
            var user = repository.GetByApiKey(apiKey);

            Assert.NotNull(user);
        }

        private User CreateUser()
        {
            var user = new User { Name = Name };

            user.ApiSetting.Allowed = true;
            user.ApiSetting.DailyLimit = 1000;
            user.ApiSetting.Key = Guid.NewGuid().ToString().ToUpperInvariant();

            repository.Add(user);
            unitOfWork.Commit();

            return user;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When we run the above test, it will generate the following SQL statements, which I think is pretty much optimized:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GetById&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:5f68e2fd-9843-41a2-8892-0bb147ef0617" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;exec sp_executesql N'SELECT 
[Limit1].[Id] AS [Id], 
[Limit1].[Name] AS [Name], 
[Limit1].[Email] AS [Email], 
[Limit1].[IsLockedOut] AS [IsLockedOut], 
[Limit1].[CreatedAt] AS [CreatedAt], 
[Limit1].[Role] AS [Role], 
[Limit1].[LastActivityAt] AS [LastActivityAt], 
[Limit1].[C1] AS [C1], 
[Limit1].[ApiKey] AS [ApiKey], 
[Limit1].[ApiAllowed] AS [ApiAllowed], 
[Limit1].[DailyLimit] AS [DailyLimit]
FROM ( SELECT TOP (2) 
	[Extent1].[Id] AS [Id], 
	[Extent1].[Name] AS [Name], 
	[Extent1].[Email] AS [Email], 
	[Extent1].[IsLockedOut] AS [IsLockedOut], 
	[Extent1].[CreatedAt] AS [CreatedAt], 
	[Extent1].[Role] AS [Role], 
	[Extent1].[ApiKey] AS [ApiKey], 
	[Extent1].[ApiAllowed] AS [ApiAllowed], 
	[Extent1].[DailyLimit] AS [DailyLimit], 
	[Extent1].[LastActivityAt] AS [LastActivityAt], 
	1 AS [C1]
	FROM [dbo].[User] AS [Extent1]
	WHERE [Extent1].[Id] = @p__linq__0
)  AS [Limit1]',N'@p__linq__0 bigint',@p__linq__0=125&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;GetByName&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:88c68121-7560-4144-bc09-e9f6403c6a86" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;exec sp_executesql N'SELECT 
[Limit1].[Id] AS [Id], 
[Limit1].[Name] AS [Name], 
[Limit1].[Email] AS [Email], 
[Limit1].[IsLockedOut] AS [IsLockedOut], 
[Limit1].[CreatedAt] AS [CreatedAt], 
[Limit1].[Role] AS [Role], 
[Limit1].[LastActivityAt] AS [LastActivityAt], 
[Limit1].[C1] AS [C1], 
[Limit1].[ApiKey] AS [ApiKey], 
[Limit1].[ApiAllowed] AS [ApiAllowed], 
[Limit1].[DailyLimit] AS [DailyLimit]
FROM ( SELECT TOP (2) 
	[Extent1].[Id] AS [Id], 
	[Extent1].[Name] AS [Name], 
	[Extent1].[Email] AS [Email], 
	[Extent1].[IsLockedOut] AS [IsLockedOut], 
	[Extent1].[CreatedAt] AS [CreatedAt], 
	[Extent1].[Role] AS [Role], 
	[Extent1].[ApiKey] AS [ApiKey], 
	[Extent1].[ApiAllowed] AS [ApiAllowed], 
	[Extent1].[DailyLimit] AS [DailyLimit], 
	[Extent1].[LastActivityAt] AS [LastActivityAt], 
	1 AS [C1]
	FROM [dbo].[User] AS [Extent1]
	WHERE [Extent1].[Name] = @p__linq__0
)  AS [Limit1]',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'http://kazimanzurrashid.myopenid.com/'&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GetByApiKey&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:1bee37b7-31c6-4fb2-b8f5-5e3c0a0868c6" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;exec sp_executesql N'SELECT 
[Limit1].[Id] AS [Id], 
[Limit1].[Name] AS [Name], 
[Limit1].[Email] AS [Email], 
[Limit1].[IsLockedOut] AS [IsLockedOut], 
[Limit1].[CreatedAt] AS [CreatedAt], 
[Limit1].[Role] AS [Role], 
[Limit1].[LastActivityAt] AS [LastActivityAt], 
[Limit1].[C1] AS [C1], 
[Limit1].[ApiKey] AS [ApiKey], 
[Limit1].[ApiAllowed] AS [ApiAllowed], 
[Limit1].[DailyLimit] AS [DailyLimit]
FROM ( SELECT TOP (2) 
	[Extent1].[Id] AS [Id], 
	[Extent1].[Name] AS [Name], 
	[Extent1].[Email] AS [Email], 
	[Extent1].[IsLockedOut] AS [IsLockedOut], 
	[Extent1].[CreatedAt] AS [CreatedAt], 
	[Extent1].[Role] AS [Role], 
	[Extent1].[ApiKey] AS [ApiKey], 
	[Extent1].[ApiAllowed] AS [ApiAllowed], 
	[Extent1].[DailyLimit] AS [DailyLimit], 
	[Extent1].[LastActivityAt] AS [LastActivityAt], 
	1 AS [C1]
	FROM [dbo].[User] AS [Extent1]
	WHERE [Extent1].[ApiKey] = @p__linq__0
)  AS [Limit1]',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'9C1A8F98-9CC6-4967-8B48-269CA92833E5'&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Insert&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:025f7703-b94d-48fa-8645-7a3fd29279ab" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;exec sp_executesql N'insert [dbo].[User]([Name], [Email], [IsLockedOut], [CreatedAt], [Role], [ApiKey], [ApiAllowed], [DailyLimit], [LastActivityAt])
values (@0, null, @1, @2, @3, @4, @5, @6, @7)
select [Id]
from [dbo].[User]
where @@ROWCOUNT &amp;gt; 0 and [Id] = scope_identity()',N'@0 nvarchar(256),@1 bit,@2 datetime,@3 int,@4 nchar(36),@5 bit,@6 int,@7 datetime',@0=N'http://kazimanzurrashid.myopenid.com',@1=0,@2='2009-08-02 22:04:17:067',@3=0,@4=N'9C1A8F98-9CC6-4967-8B48-269CA92833E5',@5=1,@6=1000,@7='2009-08-02 22:04:17:067'&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:7d1ef5fe-f72b-46e7-bd2a-0b316d73f8da" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;exec sp_executesql N'update [dbo].[User]
set [Email] = @0
where ([Id] = @1)
',N'@0 nvarchar(256),@1 bigint',@0=N'kazimanzurrashid@gmail.com',@1=142&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Delete&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:058de405-398e-42d7-83ff-5cb7c237e6e5" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="sql"&gt;exec sp_executesql N'delete [dbo].[User]
where ([Id] = @0)',N'@0 bigint',@0=125&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;You will find other tests in the integration test project.&lt;/p&gt;

&lt;p&gt;That is it for this post, in the next post we will discuss on other infrastructural item such shrinking logic, http content,&amp;#160; IoC etc etc.&lt;/p&gt;

&lt;p&gt;Stay tuned!!!&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f09%2f15%2fshrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-3.aspx&amp;amp;title=Shrinkr+-+Url+Shrinking+Service+Developed+with+Entity+Framework+4.0%2c+Unity%2c+ASP.NET+MVC+And+jQuery+(Part+3)"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/09/15/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-3.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7206212" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/iEPH3MhImgk" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/DDD/default.aspx">DDD</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Common+Service+Locator/default.aspx">Common Service Locator</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unity/default.aspx">Unity</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Mock/default.aspx">Mock</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unit+Test/default.aspx">Unit Test</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Best+Practise/default.aspx">Best Practise</category><category domain="http://weblogs.asp.net/rashid/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Shrinkr/default.aspx">Shrinkr</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/09/15/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-3.aspx</feedburner:origLink></item><item><title>Shrinkr - Url Shrinking Service Developed with Entity Framework 4.0, Unity, ASP.NET MVC And jQuery (Part 2)</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/2rG_Trc7n6Y/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-2.aspx</link><pubDate>Sun, 13 Sep 2009 09:02:36 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7203530</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>16</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7203530</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7203530</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/09/13/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-2.aspx#comments</comments><description>&lt;p&gt;In the &lt;a href="http://weblogs.asp.net/rashid/archive/2009/09/10/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-1.aspx" target="_blank"&gt;previous post&lt;/a&gt; we have created our initial domain model, in this post I will show you how the domain model&amp;#160; is mapped to database with Entity Framework 4.0. But before that I would like to discuss how I usually structure the Visual Studio Projects. Most often I prefer to have a one class library and one web project where each has its own unit test project and only one integration test project, for example:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Shrinkr.Core &lt;/li&gt;    &lt;li&gt;Shrinkr.Core.UnitTest &lt;/li&gt;    &lt;li&gt;Shrinkr.Web &lt;/li&gt;    &lt;li&gt;Shrinkr.Web.UnitTest &lt;/li&gt;    &lt;li&gt;Shrinkr.IntegrationTest &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The Core Project is then further divided into following folders:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Shrink.Core      &lt;ul&gt;       &lt;li&gt;Common (Utility, Invariant etc etc) &lt;/li&gt;        &lt;li&gt;EntityObjects (Contains both domain objects and DTOs) &lt;/li&gt;        &lt;li&gt;Extensions (Extension methods) &lt;/li&gt;        &lt;li&gt;Repositories (Contains both interface and implementation) &lt;/li&gt;        &lt;li&gt;Services (Contains both interface and implementation) &lt;/li&gt;        &lt;li&gt;Infrastructure          &lt;ul&gt;           &lt;li&gt;Caching &lt;/li&gt;            &lt;li&gt;Database &lt;/li&gt;            &lt;li&gt;Email &lt;/li&gt;            &lt;li&gt;FileSystem &lt;/li&gt;            &lt;li&gt;Http &lt;/li&gt;            &lt;li&gt;IoC &lt;/li&gt;            &lt;li&gt;Logging &lt;/li&gt;            &lt;li&gt;etc etc etc. &lt;/li&gt;         &lt;/ul&gt;       &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;But since it is an open source project, I should give privilege to community to replace any part of if with the their preferred technology. for example, replacing Entity Framework with NHibernate or may be Azure Storage, Unity with StructureMap or NInject etc etc. So I decided to structure it based upon the component dependency.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/SoutionExplorer_27C63854.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SoutionExplorer" border="0" alt="SoutionExplorer" src="http://weblogs.asp.net/blogs/rashid/SoutionExplorer_thumb_13504CFC.png" width="434" height="538" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;As you can understand that the Shrinkr.Infrastructure.Microsoft.Practices will contain the Unity and other EntLib related codes and Shrinkr.Infrastructure.EntityFramework for the concrete repositories and other data access codes. Although Entity Framework Team has released few more add-ons (known as Features CTP1), but for the time being we will not use those. The first thing we will do is create a new class which inherits from the &lt;code&gt;ObjectContext&lt;/code&gt;, lets name it as &lt;code&gt;Database&lt;/code&gt;.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Database&lt;/strong&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:30953c94-8b83-446a-9f3a-91526cf60de5" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    using System.Data.Objects;
    using System.Diagnostics;

    public class Database : ObjectContext
    {
        private IObjectSet&amp;lt;User&amp;gt; users;
        private IObjectSet&amp;lt;ShortUrl&amp;gt; shortUrls;
        private IObjectSet&amp;lt;Alias&amp;gt; aliases;
        private IObjectSet&amp;lt;Visit&amp;gt; visits;

        public Database(IConfigurationManager configurationManager, string connectionStringName) : base(GetConnectionString(configurationManager, connectionStringName), "ShrinkrEntities")
        {
            ContextOptions.DeferredLoadingEnabled = true;
        }

        public IObjectSet&amp;lt;User&amp;gt; Users
        {
            [DebuggerStepThrough]
            get
            {
                if (users == null)
                {
                    users = ObjectSet&amp;lt;User&amp;gt;();
                }

                return users;
            }
        }

        public IObjectSet&amp;lt;ShortUrl&amp;gt; ShortUrls
        {
            [DebuggerStepThrough]
            get
            {
                if (shortUrls == null)
                {
                    shortUrls = ObjectSet&amp;lt;ShortUrl&amp;gt;();
                }

                return shortUrls;
            }
        }

        public IObjectSet&amp;lt;Alias&amp;gt; Aliases
        {
            [DebuggerStepThrough]
            get
            {
                if (aliases == null)
                {
                    aliases = ObjectSet&amp;lt;Alias&amp;gt;();
                }

                return aliases;
            }
        }

        public IObjectSet&amp;lt;Visit&amp;gt; Visits
        {
            [DebuggerStepThrough]
            get
            {
                if (visits == null)
                {
                    visits = ObjectSet&amp;lt;Visit&amp;gt;();
                }

                return visits;
            }
        }

        public virtual IObjectSet&amp;lt;TEntity&amp;gt; ObjectSet&amp;lt;TEntity&amp;gt;() where TEntity : class, IEntity
        {
            return CreateObjectSet&amp;lt;TEntity&amp;gt;();
        }

        public virtual void Commit()
        {
            SaveChanges();
        }

        private static string GetConnectionString(IConfigurationManager configurationManager, string connectionStringName)
        {
            Check.Argument.IsNotNull(configurationManager, "configurationManager");
            Check.Argument.IsNotNullOrEmpty(connectionStringName, "connectionStringName");

            string connectionString = configurationManager.ConnectionString(connectionStringName);

            return connectionString;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Nothing complex, we are just exposing our Domain Entities as properties like &lt;code&gt;Users&lt;/code&gt;, &lt;code&gt;ShortUrls&lt;/code&gt;, &lt;code&gt;Aliases&lt;/code&gt; etc. One important thing you should check in the above code is that instead of using the &lt;code&gt;CreateObjectSet&amp;lt;T&amp;gt;()&lt;/code&gt; in the properties, I have created a &lt;code&gt;virtual&lt;/code&gt; method &lt;code&gt;ObjectSet&amp;lt;T&amp;gt;()&lt;/code&gt; which in turns calls the &lt;code&gt;CreateObjectSet&amp;lt;T&amp;gt;&lt;/code&gt;. The reasons behind creating this new &lt;code&gt;virtual&lt;/code&gt; method are:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code&gt;CreateObjectSet&amp;lt;T&amp;gt;&lt;/code&gt; does not return &lt;code&gt;IObjectSet&amp;lt;T&amp;gt;&lt;/code&gt;, instead it returns the concrete &lt;code&gt;ObjectSet&amp;lt;T&amp;gt;&lt;/code&gt;. &lt;/li&gt;

  &lt;li&gt;&lt;code&gt;CreateObjectSet&amp;lt;T&amp;gt;&lt;/code&gt; is not a &lt;code&gt;virtual&lt;/code&gt; method, which means we cannot mock it the unit tests (Although it is debatable whether to write unit tests over any Linq provider, but that is an another story). &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I am not sure why the Entity Framework team decided to return the concrete class instead of the interface also not making the method virtual, if they did, we do not have to write this workarounds and I am pretty sure many people will call it a design smell and finds it frustrating. Next, we will create the base repository which the UserRepository and ShortUrlRepository inherits. Although it is a common practise specially in the NHibernate world to have only one&amp;#160; Repository&amp;lt;T&amp;gt; instead of individual repository for each aggregate root which I will discuss in my next post.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RepositoryBase&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:26e01c74-0932-4b54-83b1-385b0b84d455" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    public abstract class RepositoryBase&amp;lt;TEntity&amp;gt; where TEntity : class, IEntity
    {
        protected RepositoryBase(Database database)
        {
            Check.Argument.IsNotNull(database, "database");

            Database = database;
        }

        protected Database Database
        {
            get;
            private set;
        }

        public virtual void Add(TEntity entity)
        {
            Check.Argument.IsNotNull(entity, "entity");

            Database.ObjectSet&amp;lt;TEntity&amp;gt;().AddObject(entity);
        }

        public virtual void Delete(TEntity entity)
        {
            Check.Argument.IsNotNull(entity, "entity");

            Database.ObjectSet&amp;lt;TEntity&amp;gt;().DeleteObject(entity);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Check that we have marked both &lt;code&gt;Add&lt;/code&gt; and &lt;code&gt;Delete&lt;/code&gt; method as &lt;code&gt;virtual&lt;/code&gt; so that the concrete repository can &lt;code&gt;override&lt;/code&gt; if it has some extra logic. Now, lets create the Unit Test for it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RepositoryBaseTests&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:e0829934-e9a0-44a8-9199-870dc690990a" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework.UnitTests
{
    using System.Collections.Generic;

    using Moq;
    using Xunit;

    public class RepositoryBaseTests
    {
        private readonly Mock&amp;lt;FakeObjectSet&amp;lt;Dummy&amp;gt;&amp;gt; objectSet;
        private readonly Mock&amp;lt;Database&amp;gt; database;
        private readonly DummyRepository repository;

        public RepositoryBaseTests()
        {
            var objects = new List&amp;lt;Dummy&amp;gt; {
                                            new Dummy { Id = 1},
                                            new Dummy { Id = 2},
                                            new Dummy { Id = 3}
                                          };

            objectSet = new Mock&amp;lt;FakeObjectSet&amp;lt;Dummy&amp;gt;&amp;gt;(objects);

            var configurationManager = new Mock&amp;lt;IConfigurationManager&amp;gt;();
            configurationManager.Setup(mgr =&amp;gt; mgr.ConnectionString(It.IsAny&amp;lt;string&amp;gt;())).Returns("Dummy Connection String");

            database = new Mock&amp;lt;Database&amp;gt;(configurationManager.Object, "Dummy");
            database.Setup(db =&amp;gt; db.ObjectSet&amp;lt;Dummy&amp;gt;()).Returns(objectSet.Object);

            repository = new DummyRepository(database.Object);
        }

        [Fact]
        public void Should_be_able_to_add()
        {
            objectSet.Setup(set =&amp;gt; set.AddObject(It.IsAny&amp;lt;Dummy&amp;gt;())).Verifiable();

            repository.Add(new Dummy());

            objectSet.Verify();
        }

        [Fact]
        public void Should_be_able_to_delete()
        {
            objectSet.Setup(set =&amp;gt; set.DeleteObject(It.IsAny&amp;lt;Dummy&amp;gt;())).Verifiable();

            repository.Delete(new Dummy());

            objectSet.Verify();
        }
   } 

    public class Dummy : IEntity
    {
        public long Id
        {
            get;
            set;
        }
    }

    public class DummyRepository : RepositoryBase&amp;lt;Dummy&amp;gt;
    {
        public DummyRepository(Database database) : base(database)
        {
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To test the &lt;code&gt;RepositoryBase&lt;/code&gt; we have to create few fake classes and in the unit test we are using those. The reason is, if we create mock of &lt;code&gt;RepositoryBase&lt;/code&gt; which methods are virtual the mock framework(Moq) will replace those, so the codes of &lt;code&gt;Add&lt;/code&gt; and &lt;code&gt;Delete&lt;/code&gt; will not be executed. By using the &lt;code&gt;DummyRepository&lt;/code&gt; we are making sure the &lt;code&gt;RepositoryBase&lt;/code&gt; methods are called. Another important thing you might have noticed that when setting up expectations on the &lt;code&gt;database.ObjectSet&lt;/code&gt; (line 28) method we are using another new class &lt;code&gt;FakeObjectSet&lt;/code&gt;. This is the another frustrating part of Entity Framework, you cannot pass/set collection of objects in the &lt;code&gt;ObjectSet&amp;lt;T&amp;gt;&lt;/code&gt;. This is what the &lt;code&gt;FakeObjectSet&lt;/code&gt; does, allowing us to pass the collection of objects so that our unit test can run properly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FakeObjectSet&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d5c108dd-d8a8-4fca-8c56-9c25715818a2" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework.UnitTests
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data.Objects;
    using System.Linq;
    using System.Linq.Expressions;

    public abstract class FakeObjectSet&amp;lt;T&amp;gt; : IObjectSet&amp;lt;T&amp;gt; where T : class
    {
        private readonly IEnumerable&amp;lt;T&amp;gt; objects;

        protected FakeObjectSet(IEnumerable&amp;lt;T&amp;gt; objects)
        {
            this.objects = objects;
        }

        public Expression Expression
        {
            get
            {
                return objects.AsQueryable().Expression;
            }
        }

        public IQueryProvider Provider
        {
            get
            {
                return objects.AsQueryable().Provider;
            }
        }

        public Type ElementType
        {
            get
            {
                return typeof(T);
            }
        }

        public abstract void AddObject(T entity);

        public abstract void Attach(T entity);

        public abstract void DeleteObject(T entity);

        public IEnumerator&amp;lt;T&amp;gt; GetEnumerator()
        {
            return objects.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, creating the concrete repositories are plain and simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UserRepository&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:63dc0a99-33e7-475d-8173-6c2fef7bbcc6" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    using System.Linq;

    public class UserRepository : RepositoryBase&amp;lt;User&amp;gt;, IUserRepository
    {
        public UserRepository(Database database) : base(database)
        {
        }

        public User GetById(long id)
        {
            Check.Argument.IsNotZeroOrNegative(id, "id");

            return Database.Users.SingleOrDefault(user =&amp;gt; user.Id == id);
        }

        public User GetByName(string name)
        {
            Check.Argument.IsNotNullOrEmpty(name, "name");

            return Database.Users.SingleOrDefault(user =&amp;gt; user.Name == name);
        }

        public User GetByApiKey(string apiKey)
        {
            Check.Argument.IsNotNullOrEmpty(apiKey, "apiKey");

            return Database.Users.SingleOrDefault(user =&amp;gt; user.ApiSetting.Key == apiKey);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;UserRepositoryTests&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f8856c62-50d1-40cd-867f-196ce7e149cf" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework.UnitTests
{
    using System;
    using System.Collections.Generic;

    using Moq;
    using Xunit;

    public class UserRepositoryTests
    {
        private const long UserId = 1;
        private const string UserName = "http://kazimanzurrashid.myopenid.com";
        private readonly static string ApiKey = Guid.NewGuid().ToString().ToUpperInvariant();

        private readonly Mock&amp;lt;Database&amp;gt; database;
        private readonly UserRepository repository;

        public UserRepositoryTests()
        {
            var users = new List&amp;lt;User&amp;gt; { new User { Id = UserId, Name = UserName } };

            users[0].ApiSetting.Key = ApiKey;

            var userSet = new Mock&amp;lt;FakeObjectSet&amp;lt;User&amp;gt;&amp;gt;(users);

            var configurationManager = new Mock&amp;lt;IConfigurationManager&amp;gt;();
            configurationManager.Setup(mgr =&amp;gt; mgr.ConnectionString(It.IsAny&amp;lt;string&amp;gt;())).Returns("Dummy Connection String");

            database = new Mock&amp;lt;Database&amp;gt;(configurationManager.Object, "Dummy");

            database.Setup(db =&amp;gt; db.ObjectSet&amp;lt;User&amp;gt;()).Returns(userSet.Object);

            repository = new UserRepository(database.Object, queryFactory);
        }

        [Fact]
        public void Should_be_able_to_get_by_id()
        {
            var user = repository.GetById(UserId);

            Assert.Equal(UserName, user.Name);
        }

        [Fact]
        public void Should_be_able_to_get_by_name()
        {
            var user = repository.GetByName(UserName);

            Assert.Equal(UserId, user.Id);
        }

        [Fact]
        public void Should_be_able_to_get_by_api_key()
        {
            var user = repository.GetByApiKey(ApiKey);

            Assert.Equal(UserId, user.Id);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;ShortUrlRepository&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:61d8681c-5405-4417-83d6-8182e77ab202" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework
{
    using System.Collections.Generic;
    using System.Linq;

    public class ShortUrlRepository : RepositoryBase&amp;lt;ShortUrl&amp;gt;, IShortUrlRepository
    {
        public ShortUrlRepository(Database database) : base(database)
        {
        }

        public ShortUrl GetById(long id)
        {
            Check.Argument.IsNotZeroOrNegative(id, "id");

            return Database.ShortUrls.SingleOrDefault(shortUrl =&amp;gt; shortUrl.Id == id);
        }

        public ShortUrl GetByHash(string hash)
        {
            Check.Argument.IsNotNullOrEmpty(hash, "hash");

            return Database.ShortUrls.SingleOrDefault(shortUrl =&amp;gt; shortUrl.Hash == hash);
        }

        public ShortUrl GetByAliasName(string aliasName)
        {
            Check.Argument.IsNotNullOrEmpty(aliasName, "aliasName");

            return Database.ShortUrls.SingleOrDefault(shortUrl =&amp;gt; shortUrl.Aliases.Any(alias =&amp;gt; alias.Name == aliasName));
        }

        public PagedResult&amp;lt;ShortUrl&amp;gt; FindByUserId(long userId, int start, int max)
        {
            Check.Argument.IsNotZeroOrNegative(userId, "userId");
            Check.Argument.IsNotNegative(start, "start");
            Check.Argument.IsNotNegative(max, "max");

            int total = Database.Aliases.Count(alias =&amp;gt; alias.User.Id == userId);

            IQueryable&amp;lt;ShortUrl&amp;gt; result = Database.Aliases.Where(alias =&amp;gt; alias.User.Id == userId)
                                                  .OrderByDescending(alias =&amp;gt; alias.CreatedAt)
                                                  .Select(alias =&amp;gt; alias.ShortUrl)
                                                  .Skip(start)
                                                  .Take(max);

            return new PagedResult&amp;lt;ShortUrl&amp;gt;(result, total);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;ShortUrlRepositoryTests&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:19336eeb-d906-48b7-b204-279beed4925c" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr.Infrastructure.EntityFramework.UnitTests
{
    using System.Collections.Generic;

    using Moq;
    using Xunit;

    public class ShortUrlRepositoryTests
    {
        private readonly Mock&amp;lt;Database&amp;gt; database;
        private readonly ShortUrlRepository repository;

        public ShortUrlRepositoryTests()
        {
            var shortUrls = new List&amp;lt;ShortUrl&amp;gt; {
                                                    new ShortUrl { Id = 1, Title = "Shrinkr.com",Url = "http://shrinkr.com", Hash = "http://shrinkr.com".Hash() },
                                                    new ShortUrl { Id = 2, Title = "DotNetShoutout.com", Url = "http://dotnetshoutout.com", Hash = "http://dotnetshoutout.com".Hash() }
                                               };

            shortUrls[1].Aliases.Add(new Alias { Name = "dtntshtt" });

            var shortUrlSet = new Mock&amp;lt;FakeObjectSet&amp;lt;ShortUrl&amp;gt;&amp;gt;(shortUrls);

            var user = new User { Id = 1 };

            var aliases = new List&amp;lt;Alias&amp;gt;{
                                            new Alias { Id = 1, User = user, ShortUrl = shortUrls[0] },
                                            new Alias { Id = 2, User = user, ShortUrl = shortUrls[1] },
                                         };

            var aliasSet = new Mock&amp;lt;FakeObjectSet&amp;lt;Alias&amp;gt;&amp;gt;(aliases);

            var configurationManager = new Mock&amp;lt;IConfigurationManager&amp;gt;();
            configurationManager.Setup(mgr =&amp;gt; mgr.ConnectionString(It.IsAny&amp;lt;string&amp;gt;())).Returns("Dummy Connection String");

            database = new Mock&amp;lt;Database&amp;gt;(configurationManager.Object, "Dummy");
            database.Setup(db =&amp;gt; db.ObjectSet&amp;lt;ShortUrl&amp;gt;()).Returns(shortUrlSet.Object);
            database.Setup(db =&amp;gt; db.ObjectSet&amp;lt;Alias&amp;gt;()).Returns(aliasSet.Object);

            repository = new ShortUrlRepository(database.Object);
        }

        [Fact]
        public void Should_be_able_to_get_by_id()
        {
            var shortUrl = repository.GetById(1);

            Assert.Equal(1, shortUrl.Id);
        }

        [Fact]
        public void Should_be_able_to_get_by_hash()
        {
            var shortUrl = repository.GetByHash("http://shrinkr.com".Hash());

            Assert.Equal(1, shortUrl.Id);
        }

        [Fact]
        public void Should_be_able_to_get_by_alias_name()
        {
            var shortUrl = repository.GetByAliasName("dtntshtt");

            Assert.Equal(2, shortUrl.Id);
        }

        [Fact]
        public void Should_be_able_to_find_by_user_id()
        {
            var shortUrls = repository.FindByUserId(1, 0, 10);

            Assert.Equal(2, shortUrls.Total);
            Assert.Equal(2, shortUrls.Result.Count);
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and that’s it, we have completed the initial implementation of our Repositories. What do you think, what it is currently lacking? Yes we are not taking the advantages of Compiled Queries. In the next post, I will show how you can use the both compiled and regular queries in your repositories.&lt;/p&gt;

&lt;p&gt;Stay tuned!!!&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f09%2f13%2fshrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-2.aspx&amp;amp;title=Shrinkr+-+Url+Shrinking+Service+Developed+with+Entity+Framework+4.0%2c+Unity%2c+ASP.NET+MVC+And+jQuery+(Part+2)"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/09/13/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-2.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7203530" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/2rG_Trc7n6Y" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/DDD/default.aspx">DDD</category><category domain="http://weblogs.asp.net/rashid/archive/tags/TDD/default.aspx">TDD</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Common+Service+Locator/default.aspx">Common Service Locator</category><category domain="http://weblogs.asp.net/rashid/archive/tags/IoC_2F00_DI/default.aspx">IoC/DI</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unity/default.aspx">Unity</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Mock/default.aspx">Mock</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unit+Test/default.aspx">Unit Test</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Best+Practise/default.aspx">Best Practise</category><category domain="http://weblogs.asp.net/rashid/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Entity+Framework/default.aspx">Entity Framework</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Shrinkr/default.aspx">Shrinkr</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/09/13/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-2.aspx</feedburner:origLink></item><item><title>Shrinkr - Url Shrinking Service Developed with Entity Framework 4.0, Unity, ASP.NET MVC And jQuery (Part 1)</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/H9iEwnAo06c/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-1.aspx</link><pubDate>Thu, 10 Sep 2009 14:22:41 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7199318</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>21</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7199318</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7199318</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/09/10/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-1.aspx#comments</comments><description>&lt;p&gt;Creating a full blown url shrinking service was pocking around in my mind for quite some time(of course by using Twitter). Since I heard quite a few good things on Entity Framework 4.0, so I decided to start with it. The first thing I usually do when developing an application is creating the domain model. But to create the domain model, we first have to define the basic functionalities:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The system will only use Open ID for authentication. &lt;/li&gt;    &lt;li&gt;User should be able to shrink url without logging in. &lt;/li&gt;    &lt;li&gt;When shrinking url, user should be able to specify alias, if alias is not specified, the system will auto generate it. &lt;/li&gt;    &lt;li&gt;Shrinked url will also have a associated webpage preview image. &lt;/li&gt;    &lt;li&gt;The system will maintain statistic of shrinked url like number of visit, referrer domain, geographic data etc. (requires login) &lt;/li&gt;    &lt;li&gt;The user should be able to reset shrinked url statistics. (requires login) &lt;/li&gt;    &lt;li&gt;Should have a REST service for creating shrinked url which will work upon the daily limit that was previously set. &lt;/li&gt;    &lt;li&gt;It should have nice web 2.0 style interface and should support adaptive rendering. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;For the above functionalities, I come up with the following Domain Entities:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/DomainObjects_39419D04.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="DomainObjects" border="0" alt="DomainObjects" src="http://weblogs.asp.net/blogs/rashid/DomainObjects_thumb_72485439.png" width="1224" height="751" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;As you can see most of entities are nothing but some getter/setter properties, please don’t think it as a &lt;a href="http://martinfowler.com/bliki/AnemicDomainModel.html" target="_blank"&gt;anemic domain model&lt;/a&gt;, in fact the url shrinking service does not have the kind of behaviors that you can put into your entities. When creating the entities one important thing I did was making the properties &lt;code&gt;virtual&lt;/code&gt;, so that Entity Framework can lazy load the associated objects (although it is not necessary for the intrinsic data types). For example, the following shows the codes of &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Alias&lt;/code&gt;:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;User&lt;/strong&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d3645167-d2ad-4251-a728-4e443c3dceeb" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Linq;

    public class User : IEntity
    {
        private ApiSetting apiSetting;

        public User()
        {
            CreatedAt = SystemTime.Now();
            LastActivityAt = SystemTime.Now();
            Aliases = new List&amp;lt;Alias&amp;gt;();
        }

        public virtual long Id
        {
            get;
            set;
        }

        public virtual string Name
        {
            get;
            set;
        }

        public virtual string Email
        {
            get;
            set;
        }

        public virtual bool IsLockedOut
        {
            get;
            set;
        }

        public virtual DateTime CreatedAt
        {
            get;
            set;
        }

        public virtual DateTime LastActivityAt
        {
            get;
            set;
        }

        public Role Role
        {
            [DebuggerStepThrough]
            get
            {
                return (Role) InternalRole;
            }

            [DebuggerStepThrough]
            set
            {
                InternalRole = (int) value;
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public virtual int InternalRole
        {
            get;
            set;
        }

        public virtual IList&amp;lt;Alias&amp;gt; Aliases
        {
            get;
            private set;
        }

        public virtual ApiSetting ApiSetting
        {
            [DebuggerStepThrough]
            get
            {
                if (apiSetting == null)
                {
                    apiSetting = new ApiSetting();
                }

                return apiSetting;
            }

            [DebuggerStepThrough]
            set
            {
                Check.Argument.IsNotNull(value, "value");

                apiSetting = value;
            }
        }

        public virtual bool CanAccessApi
        {
            get
            {
                bool canAccess=  (ApiSetting != null) &amp;amp;&amp;amp;
                                 (ApiSetting.Allowed.GetValueOrDefault()) &amp;amp;&amp;amp;
                                 (ApiSetting.DailyLimit == ApiSetting.InfiniteLimit || ApiSetting.DailyLimit &amp;gt; 0);

                return canAccess;
            }
        }

        public virtual void AllowApiAccess(int dailyLimit)
        {
            if (dailyLimit != ApiSetting.InfiniteLimit)
            {
                Check.Argument.IsNotNegative(dailyLimit, "dailyLimit");
            }

            if (string.IsNullOrEmpty(ApiSetting.Key))
            {
                ApiSetting.Key = Guid.NewGuid().ToString().ToUpperInvariant();
            }

            ApiSetting.Allowed = true;
            ApiSetting.DailyLimit = dailyLimit;
        }

        public virtual bool HasExceedsDailyLimit()
        {
            DateTime lastOneDay = SystemTime.Now().AddDays(-1);

            bool exceeded = CanAccessApi &amp;amp;&amp;amp;
                            ((ApiSetting.DailyLimit != ApiSetting.InfiniteLimit) &amp;amp;&amp;amp;
                             (ApiSetting.DailyLimit &amp;lt;= Aliases.Count(alias =&amp;gt; alias.CreatedAt &amp;gt; lastOneDay &amp;amp;&amp;amp; alias.CreatedByApi)));

            return exceeded;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alias:&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:38b46359-38b1-41ab-a04b-afc51755d404" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace Shrinkr
{
    using System;
    using System.Collections.Generic;

    public class Alias : IEntity
    {
        public Alias()
        {
            Visits = new List&amp;lt;Visit&amp;gt;();
            CreatedAt = SystemTime.Now();
        }

        public virtual long Id
        {
            get;
            set;
        }

        public virtual string Name
        {
            get;
            set;
        }

        public virtual string IPAddress
        {
            get;
            set;
        }

        public virtual DateTime CreatedAt
        {
            get;
            set;
        }

        public virtual IList&amp;lt;Visit&amp;gt; Visits
        {
            get;
            private set;
        }

        public virtual User User
        {
            get;
            set;
        }

        public virtual ShortUrl ShortUrl
        {
            get;
            set;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, define the Repositories, in the above entities there are two aggregate root &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;ShortUrl&lt;/code&gt;, so we will create repositories for those two:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repositories:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/Repositories_5361BA8E.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Repositories" border="0" alt="Repositories" src="http://weblogs.asp.net/blogs/rashid/Repositories_thumb_362BECB7.png" width="654" height="518" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last thing in the domain model is the Services. Please don’t confuse the Service with the Web Service or something else, here Service refers to some domain logic which does not belongs to entities or repositories, usually these services are called from the presentation layer in our case the ASP.NET MVC Controllers. In this application, we do have few things that directly does not belongs to the above entities or repositories, For example, shrinking url, ensuring unique alias etc etc. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Services:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/Services_3E7F9C41.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Services" border="0" alt="Services" src="http://weblogs.asp.net/blogs/rashid/Services_thumb_247BB652.png" width="504" height="248" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;If you are wondering about the purpose of &lt;code&gt;FindByUser&lt;/code&gt; and &lt;code&gt;GetByAlias&lt;/code&gt; method of the above &lt;code&gt;IShortUrlService&lt;/code&gt; as they already exits in &lt;code&gt;IShortUrlRepository&lt;/code&gt;, let me tell you that returning Domain Entities directly in presentation layer is not a good practise, instead you should create some Data Transfer Objects AKA DTO for returning those. The above two methods should do those kind of mappings - flattering the object hierarchy, so that we can easily map it in the UI and do serialization when required. In this application we will have the following two dtos:&lt;/p&gt;

&lt;p&gt;
  &lt;br /&gt;&lt;strong&gt;DTOs:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/DataTransferObjects_17A16034.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="DataTransferObjects" border="0" alt="DataTransferObjects" src="http://weblogs.asp.net/blogs/rashid/DataTransferObjects_thumb_756954AD.png" width="564" height="325" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;So far we have discussed about application domain model, In the next post, we will disscuss about the domain model mapping to database with Entity Framework 4.0.&lt;/p&gt;

&lt;p&gt;Stay tuned!!!&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f09%2f10%2fshrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-1.aspx&amp;amp;title=Shrinkr+-+Url+Shrinking+Service+Developed+with+Entity+Framework+4.0%2c+Unity%2c+ASP.NET+MVC+And+jQuery+(Part+1)"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/09/10/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-1.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7199318" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/H9iEwnAo06c" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/DDD/default.aspx">DDD</category><category domain="http://weblogs.asp.net/rashid/archive/tags/TDD/default.aspx">TDD</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Common+Service+Locator/default.aspx">Common Service Locator</category><category domain="http://weblogs.asp.net/rashid/archive/tags/IoC_2F00_DI/default.aspx">IoC/DI</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unity/default.aspx">Unity</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Mock/default.aspx">Mock</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Unit+Of+Work/default.aspx">Unit Of Work</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Best+Practise/default.aspx">Best Practise</category><category domain="http://weblogs.asp.net/rashid/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Entity+Framework/default.aspx">Entity Framework</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Shrinkr/default.aspx">Shrinkr</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/09/10/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-1.aspx</feedburner:origLink></item><item><title>ASP.NET MVC and Authorization and Monkey Patching</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/RCd42SWh_UM/asp-net-mvc-and-authorization-and-monkey-patching.aspx</link><pubDate>Sun, 06 Sep 2009 09:06:51 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7194251</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>8</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7194251</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7194251</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/09/06/asp-net-mvc-and-authorization-and-monkey-patching.aspx#comments</comments><description>&lt;p&gt;&lt;strong&gt;[Update: Maarten Balliauw confirmed that he has applied the suggested fix in MVC Sitemap provider]&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;As you know that we will be including Menu in our &lt;a href="http://www.telerik.com/products/aspnet-mvc.aspx" target="_blank"&gt;final release&lt;/a&gt;, when defining the menu, it will allow to specify the Route Name, Controller/Action name and associated route values for an menu item so that we can generate the corresponding url. One of the basic feature that we want to include is, when rendering the Menu it will scan through the controller’s actions and only render the menu items that the currently visiting user has permission. As you can guess, it is related with the &lt;code&gt;AuthorizeAttribute&lt;/code&gt; of ASP.NET MVC framework. The actual method that is responsible for checking the permission of this attribute is &lt;code&gt;AuthorizeCore&lt;/code&gt; which is marked as &lt;code&gt;protected&lt;/code&gt;, so there is no way we can call this method from our code. So I decided to check, how other peoples are handling this issue, so far I have found two solutions:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;ASP.NET MVC Sitemap provider of &lt;a href="http://blog.maartenballiauw.be/post/2009/09/04/ASPNET-MVC-MvcSiteMapProvider-released.aspx" target="_blank"&gt;Maarten Balliauw&lt;/a&gt; and &lt;/li&gt;    &lt;li&gt;&lt;a href="http://mvccontrib.org/" target="_blank"&gt;MVCContrib.org&lt;/a&gt;. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;But none of them are actually handling it correctly!!!.&lt;/p&gt;  &lt;p&gt;Before moving to what is wrong with these solutions, let me paste the main portion of the &lt;code&gt;AuthorizeAttribute&lt;/code&gt; code that is responsible for checking the permission:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:42f87ee1-f575-4d5f-ac12-65ac340f140a" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
    public virtual void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        if (AuthorizeCore(filterContext.HttpContext))
        {
            HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
            cachePolicy.SetProxyMaxAge(new TimeSpan(0));
            cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
        }
        else
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }
    }

    protected virtual bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext == null)
        {
            throw new ArgumentNullException("httpContext");
        }

        IPrincipal user = httpContext.User;

        if (!user.Identity.IsAuthenticated)
        {
            return false;
        }

        if (_usersSplit.Length &amp;gt; 0 &amp;amp;&amp;amp; !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
        {
            return false;
        }

        if (_rolesSplit.Length &amp;gt; 0 &amp;amp;&amp;amp; !_rolesSplit.Any(user.IsInRole))
        {
            return false;
        }

        return true;
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see the only &lt;code&gt;public&lt;/code&gt; method &lt;code&gt;OnAuthorization&lt;/code&gt; (which is also an implementation of &lt;code&gt;IAuthorizationFilter&lt;/code&gt; interface, we will discuss this interface after a little while) is calling the protected AuthorizeCore to check the permission, if it is permitted then it is adding some callback to sync with the ASP.NET Caching otherwise it returns Unauthorized Result.&lt;/p&gt;

&lt;p&gt;Now lets see, what is wrong with the above two solutions, First the ASP.NET MVC SiteMap provider, the code that is responsible for checking the controller/action permission is the following: 
  &lt;br /&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:c6ae1860-b26a-42fb-a79b-76cbfb33d20a" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;IController controller = provider.GetController(requestContext, mvcNode.Controller); // get controller
if (controller is ControllerBase)
{
    var controllerContext = new ControllerContext(requestContext, (ControllerBase)controller);
    var authorizationContext = new AuthorizationContext(controllerContext);

    foreach (IAuthorizationFilter att in controller.GetType().GetCustomAttributes(typeof(IAuthorizationFilter), true).Union(// get controller authorization filters
    controller.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(m =&amp;gt;
    {
        var nameAtt = m.GetCustomAttributes(typeof(ActionNameAttribute), true).FirstOrDefault() as ActionNameAttribute;
        return string.Equals(mvcNode.Action, nameAtt != null ? nameAtt.Name : m.Name, StringComparison.OrdinalIgnoreCase);
    })
    .SelectMany(m =&amp;gt; m.GetCustomAttributes(typeof(IAuthorizationFilter), true))))// get authorization filters from all related methods
    {
        if (att is ValidateAntiForgeryTokenAttribute)
        {
            return true;
        }
        att.OnAuthorization(authorizationContext); // run authorization
        if (authorizationContext.Result != null) // authorization failed
        {
            return false;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;There are two issues with the above code:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It depends upon the &lt;code&gt;IAuthorizationFilter&lt;/code&gt; rather than &lt;code&gt;AuthorizeAttribute&lt;/code&gt;, the problem with this approach is there more filters other than &lt;code&gt;AuthorizeAttribute&lt;/code&gt; which implements this interface, as you can see there is a check for &lt;code&gt;ValidateAntiForgeryTokenAttribute&lt;/code&gt; in the above code, there are few more already in the ASP.NET MVC Framework e.g. &lt;code&gt;ValidateInputAttribute&lt;/code&gt;, &lt;code&gt;RequireSslAttribute&lt;/code&gt; and anyone can write a custom filter that implements this interface and decorate the controller/action, so this code will return incorrect results, in those cases. &lt;/li&gt;

  &lt;li&gt;The next issue, when it is executed for &lt;code&gt;AuthorizeAttribute&lt;/code&gt; which in turns adds caching callback and there is no way to remove that callback once the &lt;code&gt;OnAuthorization&lt;/code&gt; calls gets completed, so it will screw the ASP.NET Caching and might hurt the application performance. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The correct way to address this issue:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Don’t depend on the &lt;code&gt;IAuthorizationFilter&lt;/code&gt; interface, instead check the concrete &lt;code&gt;AuthorizeAttribute&lt;/code&gt; which is meant to be dealing with Roles/Users, also it is not marked as &lt;code&gt;sealed,&lt;/code&gt; so it is expected that you will be inheriting this class and &lt;code&gt;override&lt;/code&gt; the &lt;code&gt;AuthorizeCore&lt;/code&gt; method if you want to put your custom logic. &lt;/li&gt;

  &lt;li&gt;Find a way to call the &lt;code&gt;protected AuthorizeCore&lt;/code&gt; method which is actually responsible for checking the permission. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, lets see how the MVCContrib team is handling this issue, basically they have created a new class inherited from the &lt;code&gt;AuthorizeAttribute&lt;/code&gt; and it also contains a &lt;code&gt;public&lt;/code&gt; method &lt;code&gt;Authorized&lt;/code&gt; which in turn calls the &lt;code&gt;protected AuthorizeCore&lt;/code&gt; method:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:8d3837bf-1450-474f-91c8-24a1933964f7" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class OpenAuthorizeAttribute : AuthorizeAttribute
{
    public OpenAuthorizeAttribute(AuthorizeAttribute attribute)
    {
        Order = attribute.Order;
        Roles = attribute.Roles;
        Users = attribute.Users;
    }

    public bool Authorized(RequestContext requestContext)
    {
        return AuthorizeCore(requestContext.HttpContext);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;And whenever they wants to check permission they pass the actual attribute to this new class and calls the &lt;code&gt;Authorized&lt;/code&gt; method. Much better than the previous solution, still it will not work when you create a Custom &lt;code&gt;AuthorizationAttribute&lt;/code&gt;, as it will call the &lt;code&gt;AuthorizeCore&lt;/code&gt; of the original &lt;code&gt;AuthorizationAttribute&lt;/code&gt; rather than yours.&lt;/p&gt;

&lt;p&gt;After discussing with the ASP.NET MVC Team and Levi Broderick explained me really well that &lt;code&gt;AuthorizeAttribute&lt;/code&gt; was not really designed to be used in this kind of scenario.To solve it, yes we can use &lt;code&gt;InvokeMethod&lt;/code&gt; of reflection, but invoking a protected method will not work in medium trust environment. So the only option that is left to monkey patch this issue is IL rewritting. The logic is, when checking the permission it will check whether a custom &lt;code&gt;AuthorizeAttribute&lt;/code&gt; is used, if not it will follow the same as the MVCContrib is currently doing, if a custom Authorization attribute is used, it will runtime create a inherited class with a public method which we will call to check the permission, of course there is slight a performance overhead associated, but we can easily overcome it with proper caching. Now lets take a quick look how we are checking whether the user has permission of an action, assuming that the AuthorizeAttributes are collected from another service:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:63c37336-4c92-47d8-b366-56935ff0b276" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;foreach (AuthorizeAttribute authorizationAttribute in authorizationAttributes)
{
    if (authorizationAttribute != null)
    {
        try
        {
            Type currentAuthorizationAttributeType = authorizationAttribute.GetType();

            IAuthorizeAttribute subclassedAttribute = (currentAuthorizationAttributeType == typeof(AuthorizeAttribute)) ?
                                                       new InternalAuthorize() : // No need to use Reflection.Emit when asp.net mvc built-in attribute is used
                                                       reflectedAuthorizeAttributeCache.GetAttribute(currentAuthorizationAttributeType);

            subclassedAttribute.Order = authorizationAttribute.Order;
            subclassedAttribute.Roles = authorizationAttribute.Roles;
            subclassedAttribute.Users = authorizationAttribute.Users;

            // Copy the remaining properties (if there is any)
            objectCopier.Copy(authorizationAttribute, subclassedAttribute, "Order", "Roles", "Users" /* Excluded properties */);

            allowed = subclassedAttribute.IsAuthorized(requestContext.HttpContext);
        }
        catch
        {
            // do not allow on exception
            allowed = false;
        }

        if (!allowed)
        {
            break;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;As you can see when the default &lt;code&gt;AuthorizeAttribute&lt;/code&gt; is used we are creating &lt;code&gt;InternalAttribute&lt;/code&gt;, if not we are requesting a caching service to get the runtime version of this attribute, for each custom attribute we are using Reflection.Emit to create a subclass of that attribute and then we are caching it so that we can use the same attribute without recreating it with Reflection.Emit. Also to avoid naming collision, we created an interface &lt;code&gt;IAuthorizeAttribute&lt;/code&gt; which we implements with IL. The &lt;code&gt;IAuthorizeAttribute&lt;/code&gt; contains the same properties as the original &lt;code&gt;AuthorizeAttribute&lt;/code&gt;: &lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:cbdc7f66-3eed-4dc0-8811-f678d12bbe92" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public interface IAuthorizeAttribute
{
    int Order
    {
        get;
        set;
    }

    string Roles
    {
        get;
        set;
    }

    string Users
    {
        get;
        set;
    }

    bool IsAuthorized(HttpContextBase httpContext);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now here is the magic code that generates the class at runtime:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f51d0a47-34b3-4d35-8828-e96d71cdd68f" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;// (c) Copyright Telerik Corp. 
// This source is subject to the Microsoft Public License. 
// See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL. 
// All other rights reserved.

namespace Telerik.Web.Mvc.Infrastructure.Implementation
{
    using System;
    using System.Reflection;
    using System.Reflection.Emit;
    using System.Web;

    public class AuthorizeAttributeBuilder : IAuthorizeAttributeBuilder
    {
        private static readonly Type authorizeAttributeType = typeof(IAuthorizeAttribute);
        private static readonly ModuleBuilder module = CreateModuleBuilder();

        public ConstructorInfo Build(Type parentType)
        {
            Guard.IsNotNull(parentType, "parentType");

            string typeName = "$" + parentType.FullName.Replace(".", string.Empty);

            TypeBuilder typeBuilder = module.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit, parentType, new[] { authorizeAttributeType });
            typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
            typeBuilder.AddInterfaceImplementation(authorizeAttributeType);

            WriteProperty(parentType, typeBuilder, "Order", typeof(int));
            WriteProperty(parentType, typeBuilder, "Roles", typeof(string));
            WriteProperty(parentType, typeBuilder, "Users", typeof(string));
            WriteIsAuthorized(parentType, typeBuilder);

            Type type = typeBuilder.CreateType();

            return type.GetConstructor(Type.EmptyTypes);
        }

        private static void WriteProperty(Type parentType, TypeBuilder builder, string name, Type type)
        {
            string getName = "get_" + name;
            string setName = "set_" + name;

            MethodInfo parentGetMethod = parentType.GetMethod(getName, BindingFlags.Public | BindingFlags.Instance);
            MethodBuilder implementedGetMethod = builder.DefineMethod(getName, MethodAttributes.Public | MethodAttributes.Virtual, type, Type.EmptyTypes);
            ILGenerator getIl = implementedGetMethod.GetILGenerator();
            getIl.Emit(OpCodes.Ldarg_0);
            getIl.Emit(OpCodes.Call, parentGetMethod);
            getIl.Emit(OpCodes.Ret);

            MethodInfo interfaceGetMethod = authorizeAttributeType.GetMethod(getName, BindingFlags.Public | BindingFlags.Instance);
            builder.DefineMethodOverride(implementedGetMethod, interfaceGetMethod);

            MethodInfo parentSetMethod = parentType.GetMethod(setName, BindingFlags.Public | BindingFlags.Instance);
            MethodBuilder implementedSetMethod = builder.DefineMethod(setName, MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), new[] { type });
            ILGenerator setIl = implementedSetMethod.GetILGenerator();
            setIl.Emit(OpCodes.Ldarg_0);
            setIl.Emit(OpCodes.Ldarg_1);
            setIl.Emit(OpCodes.Call, parentSetMethod);
            setIl.Emit(OpCodes.Ret);

            MethodInfo interfaceSetMethod = authorizeAttributeType.GetMethod(setName, BindingFlags.Public | BindingFlags.Instance);
            builder.DefineMethodOverride(implementedSetMethod, interfaceSetMethod);
        }

        private static void WriteIsAuthorized(Type parentType, TypeBuilder builder)
        {
            MethodInfo protectedMethod = parentType.GetMethod("AuthorizeCore", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod);
            MethodBuilder implementedMethod = builder.DefineMethod("IsAuthorized", MethodAttributes.Public | MethodAttributes.Virtual, typeof(bool), new[] { typeof(HttpContextBase) });
            ILGenerator il = implementedMethod.GetILGenerator();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Call, protectedMethod);
            il.Emit(OpCodes.Ret);

            MethodInfo interfaceMethod = authorizeAttributeType.GetMethod("IsAuthorized", BindingFlags.Public | BindingFlags.Instance);
            builder.DefineMethodOverride(implementedMethod, interfaceMethod);
        }

        private static ModuleBuilder CreateModuleBuilder()
        {
            const string Name = "InheritedAuthorizeAttributes";

            AssemblyName assemblyName = new AssemblyName(Name + "Assembly")
                                            {
                                                Version = typeof(AuthorizeAttributeBuilder).Assembly.GetName().Version
                                            };

            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(Name + "Module");

            return moduleBuilder;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There is only one public method &lt;code&gt;Build&lt;/code&gt; where you have to pass the custom &lt;code&gt;AuthorizeAttribute&lt;/code&gt; type, the rest will be taken care by it. And if you want to use the above code, you are permitted to do so, as it is licensed under MS-PL.&lt;/p&gt;

&lt;p&gt;The moral of this story is though ASP.NET MVC is one of the most extensible framework by MS, yet there are some places where it requires some re-work, but it does not mean you would say some harsh word like some negative minded people of our community, instead you should look for the solution and share it.&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f09%2f06%2fasp-net-mvc-and-authorization-and-monkey-patching.aspx&amp;amp;title=ASP.NET+MVC+and+Authorization+and+Monkey+Patching"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/09/06/asp-net-mvc-and-authorization-and-monkey-patching.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7194251" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/RCd42SWh_UM" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Telerik/default.aspx">Telerik</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/09/06/asp-net-mvc-and-authorization-and-monkey-patching.aspx</feedburner:origLink></item><item><title>Telerik Extensions for ASP.NET MVC – Upcoming ScriptRegistrar Preview</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/RscZfTugsfs/telerik-extensions-for-asp-net-mvc-upcoming-scriptregistrar-preview.aspx</link><pubDate>Sat, 29 Aug 2009 08:45:56 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7184971</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>8</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7184971</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7184971</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/08/29/telerik-extensions-for-asp-net-mvc-upcoming-scriptregistrar-preview.aspx#comments</comments><description>&lt;p&gt;&lt;strong&gt;[Update: I have updated the images with a recent version which more clarifies the whole picture, the result shows the parallel version is 2x fast comparing to the plain.&lt;/strong&gt;&lt;strong&gt;]&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In this post, I will give you a sneak preview of the &lt;code&gt;ScriptRegistrar&lt;/code&gt; major enhancement. Those who have checked our &lt;code&gt;ScriptRegistrar&lt;/code&gt; or followed my blog for last few weeks already know that it has out of box support for Grouping. Combining, Caching, Compressing, Synchronizing statements between Master/Content and as far as I know, no other component including the other commercial vendors has all these features that we are providing for free and as well as open sourced. Currently we are working on parallel script downloading support that we are going to include in our next release, if you do not know about parallel script downloading let me first show you a regular example, lets say you have a page which contains five script tags:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9d6111fa-25bb-49e8-b80c-584d16df5b78" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;
&amp;lt;html xmlns="http://www.w3.org/1999/xhtml" &amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Plain Script Loading&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Plain Script Loading example&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;Here goes the sample body..&amp;lt;/p&amp;gt;
    &amp;lt;div id="status" style="font-family:Consolas;background-color:#ccc"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;% string ticks = DateTime.Now.Ticks.ToString(); %&amp;gt;
    &amp;lt;script type="text/javascript" src="Scripts/plainScript1.js?t=&amp;lt;%= ticks %&amp;gt;"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script type="text/javascript" src="Scripts/plainScript2.js?t=&amp;lt;%= ticks %&amp;gt;"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script type="text/javascript" src="Scripts/plainScript3.js?t=&amp;lt;%= ticks %&amp;gt;"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script type="text/javascript" src="Scripts/plainScript4.js?t=&amp;lt;%= ticks %&amp;gt;"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script type="text/javascript" src="Scripts/plainScript5.js?t=&amp;lt;%= ticks %&amp;gt;"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script type="text/javascript"&amp;gt;
        document.getElementById('status').innerHTML += 'You must have seen all the messages.&amp;lt;br&amp;gt;';
    &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you run the above page with Firebug, you will find, it loads the page similar to the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/plain_3E6E4D66.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="plain" border="0" alt="plain" src="http://weblogs.asp.net/blogs/rashid/plain_thumb_2EDB15CA.png" width="1266" height="501" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Check the above red marked area which shows as steps of a stairway. It indicates when a browser encounters a script tag it stops its rendering until it downloads the script file. Since we have included five script files there are five steps (total six, the first one is for the page), each for a script. Now lets add the same number of script files with our &lt;code&gt;ScriptRegistrar&lt;/code&gt;:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:4160924b-ed8c-4129-92ef-5ce326807cf1" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;
&amp;lt;html xmlns="http://www.w3.org/1999/xhtml" &amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Next ScriptRegistrar&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;ScriptRegistrar : Parallel script loading example&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;Here goes the sample body..&amp;lt;/p&amp;gt;
    &amp;lt;div id="status" style="font-family:Consolas;background-color:#ccc"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;% string ticks = DateTime.Now.Ticks.ToString(); %&amp;gt;
    &amp;lt;% Html.Telerik().ScriptRegistrar()
                     .Scripts(script =&amp;gt;
                              script.Add("~/Scripts/parallelScript1.js?t=" + ticks)
                                    .Add("~/Scripts/parallelScript2.js?t=" + ticks)
                                    .Add("~/Scripts/parallelScript3.js?t=" + ticks)
                                    .Add("~/Scripts/parallelScript4.js?t=" + ticks)
                                    .Add("~/Scripts/parallelScript5.js?t=" + ticks)
                             )
                     .OnDocumentReady(() =&amp;gt;
                                      {%&amp;gt;
                                        document.getElementById('status').innerHTML += 'You must have seen all the messages.&amp;lt;br&amp;gt;';
                                      &amp;lt;%}
                                     )
                     .Render(); %&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(I have intentionally removed the default jQuery script form the &lt;code&gt;ScriptRegistrar&lt;/code&gt; and did not merge it as a group to show the parallelization).&lt;/p&gt;

&lt;p&gt;When you run the &lt;code&gt;ScriptRegistrar&lt;/code&gt; version with the Firebug, you will get the following picture:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/parallel_47F67002.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="parallel" border="0" alt="parallel" src="http://weblogs.asp.net/blogs/rashid/parallel_thumb_46EE5A58.png" width="1275" height="472" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Now check the red marked area again, as you can see there are no steps which means download of this scripts starts almost at the same time, we are initially loading our tiny script loader(&lt;code&gt;Telerik.ScriptRegistrar.js&lt;/code&gt;) which then loads these scripts without blocking each other. We are still working on different cases and how you can more easily define the dependencies between the groups/script files.&lt;/p&gt;

&lt;p&gt;So to those folks who thinks that a msbuild/nant task that minifies and combines script files of a predefined directory on post build and a &lt;code&gt;ScriptInclude&lt;/code&gt; helper method is all the optimization that can be done when it comes to script management, maybe it is okay for a small application where the number of javascript files are same or less than your hand’s finger, but for today’s highly ajax application, there are a lot of cool things that you can do to enhance its performance and we are fully committed for doing that.&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f08%2f29%2ftelerik-extensions-for-asp-net-mvc-upcoming-scriptregistrar-preview.aspx&amp;amp;title=Telerik+Extensions+for+ASP.NET+MVC+%e2%80%93+Upcoming+ScriptRegistrar+Preview"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/08/29/telerik-extensions-for-asp-net-mvc-upcoming-scriptregistrar-preview.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7184971" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/RscZfTugsfs" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Telerik/default.aspx">Telerik</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/08/29/telerik-extensions-for-asp-net-mvc-upcoming-scriptregistrar-preview.aspx</feedburner:origLink></item><item><title>Convention over Configuration and Telerik Extensions for ASP.NET MVC</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/Dx0SfSXSkF4/convention-over-configuration-and-telerik-extensions-for-asp-net-mvc.aspx</link><pubDate>Thu, 27 Aug 2009 14:03:31 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7183039</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>5</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7183039</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7183039</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/08/27/convention-over-configuration-and-telerik-extensions-for-asp-net-mvc.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Convention_over_configuration" target="_blank"&gt;Convention over Configuration&lt;/a&gt; is getting more and more popular in the .NET space, especially after the release of ASP.NET MVC. In &lt;a href="http://www.telerik.com/products/aspnet-mvc.aspx" target="_blank"&gt;our extensions&lt;/a&gt;, there are quite a few places where you will find this concept, lets consider the following snippet of &lt;code&gt;ScriptRegistrar&lt;/code&gt;:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d9248f01-f5bb-4418-93a1-fd20bb6dd25a" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.Telerik().ScriptRegistrar()
                 .Scripts(script =&amp;gt; script.AddGroup(
                                                        "validation",
                                                        group =&amp;gt; group.Add("jquery.validate.js")
                                                                      .Add("xVal.jquery.validate.js")
                                                                      .Combined(true)
                                                   )
						 )
				 .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Check that we did not mention any path for the script files, by default it assumes that all the script files are located in the default “Scripts” folder that is created when you create a ASP.NET MVC Application in Visual Studio. Now what if the script files resides in a different folder.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:ff33c685-df1d-4165-a089-239aee346617" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.Telerik().ScriptRegistrar()
                 .Scripts(script =&amp;gt; script.AddGroup(
                                                        "validation",
                                                        group =&amp;gt; group
                                                                      .DefaultPath("~/Scripts/Validation") // Setting the default path of a Group.
                                                                      .Add("jquery.validate.js")
                                                                      .Add("xVal.jquery.validate.js")
                                                                      .Combined(true)
                                                   )
						 )
				 .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now what if one of the file in a group resides in a different folder:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:556e9a60-e94b-432a-b0bd-14a4e7ecf52b" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.Telerik().ScriptRegistrar()
                 .Scripts(script =&amp;gt; script.AddGroup(
                                                        "validation",
                                                        group =&amp;gt; group
                                                                      .DefaultPath("~/Scripts/Validation")
                                                                      .Add("jquery.validate.js")
                                                                      .Add("~/SomeOtherPath/xVal.jquery.validate.js") // Check that we are setting the complete path.
                                                                      .Combined(true)
                                                   )
						 )
				 .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Okay, now what if you want to change the default location of both scripts and stylesheet files, Just add the following lines in your application start (&lt;code&gt;global.asax&lt;/code&gt; maybe):&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:40503d85-15c9-41a4-a8b0-5b5ed22864d6" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;WebAssetDefaultSettings.StyleSheetFilesPath = "~/assets/stylesheets";
WebAssetDefaultSettings.ScriptFilesPath = "~/assets/scripts";&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So by convention we are assuming the default locations (for script “~/Scripts” and Stylesheet “~/Content”) but with configuration (the above 2, 3, 4 code snippets) you can completely override it. Let me show one more case before completing this post.&lt;/p&gt;

&lt;p&gt;We all know we should minify our script and stylesheet files with tools like &lt;a href="http://developer.yahoo.com/yui/compressor/" target="_blank"&gt;Yahoo compressor&lt;/a&gt; before making the application live. Lets say we have minified the above two files with a minifying tool and saved in the Scripts directory with .min.js extension. Now, if you run the application in release mode &lt;code&gt;debug = “false”&lt;/code&gt; in &lt;code&gt;web.config,&lt;/code&gt; you will find that the &lt;code&gt;ScriptRegistrar&lt;/code&gt; is picking up the .min.js instead of .js or debug.js and the vice versa when &lt;code&gt;debug=”true”&lt;/code&gt; and the same holds true for &lt;code&gt;StyleSheetRegistrar&lt;/code&gt;.&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f08%2f27%2fconvention-over-configuration-and-telerik-extensions-for-asp-net-mvc.aspx&amp;amp;title=Convention+over+Configuration+and+Telerik+Extensions+for+ASP.NET+MVC"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/08/27/convention-over-configuration-and-telerik-extensions-for-asp-net-mvc.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7183039" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/Dx0SfSXSkF4" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Source/default.aspx">Open Source</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Telerik/default.aspx">Telerik</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/08/27/convention-over-configuration-and-telerik-extensions-for-asp-net-mvc.aspx</feedburner:origLink></item><item><title>RESTify – Extending ASP.NET MVC</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/2XSNTf1RzHg/restify-extending-asp-net-mvc.aspx</link><pubDate>Mon, 24 Aug 2009 23:41:49 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7180605</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>15</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7180605</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7180605</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/08/25/restify-extending-asp-net-mvc.aspx#comments</comments><description>&lt;p&gt;Recently there has been a talk of Actionless Controller in ASP.NET MVC space. Basically we are doing a lot of things in the controller and that is the reason we often finds our controllers with number of dependencies in the constructor. &lt;a href="http://jeffreypalermo.com/blog/the-asp-net-mvc-actioncontroller-ndash-the-controllerless-action-or-actionless-controller/" target="_blank"&gt;Jeffrey Palermo&lt;/a&gt; initially suggested a version where he separated each action as a standalone controller which is good to reduce the number of dependency but it does not sound right to me. At the bottom of that post &lt;a href="http://randomcode.net.nz/" target="_blank"&gt;Neal Blomfield&lt;/a&gt; hinted about the Command Pattern which makes absolute sense. Since the &lt;a href="http://weblogs.asp.net/rashid/archive/2009/08/12/introducing-telerik-extensions-for-asp-net-mvc.aspx" target="_blank"&gt;release of our initial version&lt;/a&gt;, I have got some time to breathe, so I decided to give it a try. Initially the idea was, each Controller action method will accept a command object as parameter and the Controller will call the Execute method. The Command object will be responsible to perform the action which the Controller action methods usually do. Let me show you a sample controller which has nothing but some CRUD methods with Command objects:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:95469116-9e01-493a-b06d-8dd9ceab5aba" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class ProductController : Controller
{
    public ActionResult Index(ProductListCommand command)
    {
        return command.Execute();
    }

    public ActionResult Create()
    {
        return View();
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(ProductCreateCommand command)
    {
        return command.Execute();
    }

    public ActionResult Edit(ProductGetCommand command)
    {
        return command.Execute();
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(ProductUpdateCommand command)
    {
        return command.Execute();
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Delete(ProductDeleteCommand command)
    {
        return command.Execute();
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, let see what is happening inside the Commands, first the &lt;code&gt;ProductCreateCommand&lt;/code&gt;:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:3b2659c9-1baa-4f14-9bdb-82f1312bea1b" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class ProductCreateCommand : RESTifyCommand
{
    private readonly IRepository&amp;lt;Product&amp;gt; repository;

    public ProductCreateCommand(IRepository&amp;lt;Product&amp;gt; repository)
    {
        this.repository = repository;
    }

    public Product Product
    {
        get;
        set;
    }

    protected override void ExecuteCore()
    {
        // You should use a powerful validation engine like DataAnnotation or xVal 
        // over here, I am using the dumb if/else for the shake of simplicity.

        if (string.IsNullOrEmpty(Product.Name))
        {
            ModelState.AddModelError("Product.Name", "Name cannot be blank.");
        }

        if (!Product.Price.HasValue)
        {
            ModelState.AddModelError("Product.Price", "Price cannot be blank.");
        }

        if (Product.Price.HasValue &amp;amp;&amp;amp; (Product.Price &amp;lt;= 0))
        {
            ModelState.AddModelError("Product.Price", "Invalid price. Price cannot be zero or negative.");
        }

        if (ModelState.IsValid)
        {
            repository.Create(Product);
            ViewData.Model = Product;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;First, it is inherited from a special base class &lt;code&gt;RESTifyCommand&lt;/code&gt;, next we are injecting our dependency in the constructor as we do for the Controllers and at last, we are overriding the &lt;code&gt;ExecuteCore&lt;/code&gt; method to perform our actual operation. Also check that we not writing any code to populate the Product, instead we are relying on the ASP.NET MVC Framework to populate it for us. The little difference between the &lt;code&gt;ExecuteCore&lt;/code&gt; with a regular Controller action method is instead of returning any &lt;code&gt;ActionResult&lt;/code&gt;(the method is a &lt;code&gt;void()&lt;/code&gt;) we are only setting up the &lt;code&gt;Model&lt;/code&gt; and &lt;code&gt;ModelState&lt;/code&gt;. I will get back to the Execute() method after a little while, for the moment lets see how this Command object is created and passed backed to the Controller. One of the important thing when creating the Command Object is, we have to inject the dependencies in its constructor or more specifically we have to give the opportunity so that you can use your prefered IoC/DI framework to create these commands, also we need to utilize the rich ASP.NET MVC underlying features to automatically populate the other parts of the Command (for ex the Product property of the above example) and the thing that I really love of ASP.NET MVC framework is its extensibility. To create and populate the Command object we use a custom &lt;code&gt;ModelBinder&lt;/code&gt;. Our &lt;code&gt;ModelBinder&lt;/code&gt; is inherited from the &lt;code&gt;DefaultModelBinder&lt;/code&gt; of ASP.NET MVC as we want to reuse the common behavior of the default binder, but instead of overriding the &lt;code&gt;BindModel&lt;/code&gt; that you often see in most of the available &lt;code&gt;ModelBinders&lt;/code&gt;, we are overriding the &lt;code&gt;CreateModel&lt;/code&gt; method.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:37892a3e-aef7-49a3-b83c-62f35cc0c764" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class CommandBinder : DefaultModelBinder
{
    private readonly Func&amp;lt;Type, IRESTifyCommand&amp;gt; factory;
    private readonly IFormatDetector formatDetector;

    public CommandBinder(Func&amp;lt;Type, IRESTifyCommand&amp;gt; factory, IFormatDetector formatDetector)
    {
        Invariant.IsNotNull(factory, "factory");
        Invariant.IsNotNull(formatDetector, "formatDetector");

        this.factory = factory;
        this.formatDetector = formatDetector;
    }

    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        Invariant.IsNotNull(controllerContext, "controllerContext");
        Invariant.IsNotNull(modelType, "modelType");

        IRESTifyCommand command = factory(modelType);
        RESTifyFormats format = formatDetector.Detect(controllerContext.HttpContext.Request);

        command.SetRequestFormat(format);
        command.SetControllerContext(controllerContext);

        return command;
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see in the constructor we are accepting a &lt;code&gt;Func&lt;/code&gt; to create the Command so that we do not have to refer to any external IoC/DI component, we are also accepting another object &lt;code&gt;IFormatDetector&lt;/code&gt;. Initially, my plan was to introduce the Command object in ASP.NET MVC, but after seeing both &lt;a href="http://kohari.org/2009/08/10/siesta-painless-rest-via-asp-net-mvc/" target="_blank"&gt;Nate Kohari’s Siesta&lt;/a&gt; and &lt;a href="http://www.haacked.com/archive/2009/08/17/rest-for-mvc.aspx" target="_blank"&gt;MS ASP.NET MVC REST SDK&lt;/a&gt;, I thought why not add some REST love into this. So the idea was after the Command objects performs its actual operation which we have seen in the above, it should also decide in which format it will return the data, the associated controller should not have any clue about this, all it has to do is call the &lt;code&gt;Excecute()&lt;/code&gt; method of command and the rest it taken care by the &lt;code&gt;Command&lt;/code&gt;. In the above, the &lt;code&gt;formatDetector&lt;/code&gt; detects the requested format from &lt;code&gt;HttpRequest&lt;/code&gt; and sets the Command requested format, so that Command can later return the result depending upon that. Although it is in very early stages and I am still working on it, yet there are some advantages of using it comparing to the above:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Out of the box support for HTML/XML/JSON/&lt;strong&gt;JSONP.&lt;/strong&gt; There is no generic representation of ATOM/RSS, you need to write special formatters(&lt;code&gt;IResultFormatter&lt;/code&gt;) to support those. &lt;/li&gt;

  &lt;li&gt;Serialization support other than &lt;code&gt;DataContractSerializer&lt;/code&gt;, which means you can serialize anything including the anonymous objects. &lt;/li&gt;

  &lt;li&gt;Support for Registering &lt;code&gt;JavaScriptConverter&lt;/code&gt; to shape up the json output. (It is still missing in the ASP.NET MVC Framework). &lt;/li&gt;

  &lt;li&gt;Support for Registering KnownTypes for the &lt;code&gt;DataContractSerializer.&lt;/code&gt; &lt;/li&gt;

  &lt;li&gt;Fully extensible, anything can be replaced without modifying the core. &lt;/li&gt;

  &lt;li&gt;200+ Unit Tests which include more than 99% code coverage. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can view the complete &lt;a href="http://216.177.71.90/RESTify/Product" target="_blank"&gt;live demo&lt;/a&gt;, over here. As you can see the same Controller method is responsible for returning different formats, no condition checking, no if/else nothing, just call the &lt;code&gt;Execute()&lt;/code&gt; of the Command. In the demo, I am using plain javascript instead of any library like jQuery/ASP.NET AJAX to show you that it is completely independent of the client side, you can use your prefered javascript library with this extension when working with your browser application.&lt;/p&gt;

&lt;p&gt;Now lets get back to the original discussion, so far we have set the &lt;code&gt;Model&lt;/code&gt; and &lt;code&gt;ModelState&lt;/code&gt;, but did not see how the result is delivered to the client, lets see what is happening in the &lt;code&gt;RESTIfyCommand&lt;/code&gt;’s &lt;code&gt;Execute&lt;/code&gt; method:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:a263a05a-e5b9-4976-aa17-8fd6b3df2a44" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public virtual ActionResult Execute()
{
    if (!CanExecute)
    {
        return Unsupported();
    }

    ExecuteCore();

    return BuildResult();
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;First, we are checking whether the Command can execute, there are severeal reasons a Command cannot execute, for example the request format is not supported by the Command, which usually happens when you want to restrict certain formats from delivering to the client or formatter for the requested type is not registered or your code as you can override the method, if the command cannot execute we are returning a special &lt;code&gt;ActionResult&lt;/code&gt; &lt;code&gt;RESTifyUnsupportedResult&lt;/code&gt; which is basically returning &lt;code&gt;HttpStatusCode&lt;/code&gt; 415(Unsupported Media Type). If the command is allowed to execute then it is calling the ExecuteCore() which means the code that we have written in the above and finally it is returning the result. Now lets see the code of &lt;code&gt;BuildResult&lt;/code&gt; method.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:fe83109d-2648-4c20-8dcd-ed5c2090615e" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;protected virtual ActionResult BuildResult()
{
    if (RequestedFormat == RESTifyFormats.Html)
    {
        return new ViewResult { ViewData = ViewData, TempData = TempData };
    }

    IResultFormatter formatter = ResultFormatters[RequestedFormat];

    if (RequestedFormat == RESTifyFormats.Jsonp)
    {
        IJsonpResultFormatter jsonpFormatter = formatter as IJsonpResultFormatter;

        if (jsonpFormatter == null)
        {
            throw new InvalidOperationException(TextResource.InvalidResultFormatterTypeRegisteredForJsonp.FormatWith(formatter.GetType().FullName));
        }

        jsonpFormatter.JsonpCallbackFunction = JsonpFunctionNameDetector.Detect(HttpContext.Request);
    }

    return new RESTifyResult(RequestedFormat, formatter, HttpContext.Request.ContentEncoding, Model, ModelState);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, for the Html, we are returning the regular ViewResult, next for JSONP we are checking whether the registered formatter is appropriate for JSONP, as JSONP needs the additional callback method name, the rest of the part is very simple, we are returning our custom &lt;code&gt;RESTifyResult&lt;/code&gt; with the required data, the &lt;code&gt;RESTifyResult&lt;/code&gt; uses the provided ResultFormatter to write in the Response.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:474f6620-a66f-4b15-a113-93faa2284471" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public override void ExecuteResult(ControllerContext context)
{
    Invariant.IsNotNull(context, "context");

    HttpResponseBase response = context.HttpContext.Response;

    response.Clear();

    response.ContentType = contentTypes[Format];

    if (ContentEncoding != null)
    {
        response.ContentEncoding = ContentEncoding;
    }

    string output = Formatter.Format(ContentEncoding, Model, ModelState);

    response.Write(output);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;One last thing that you have to do, is adding some bootstrapping code in the &lt;code&gt;global.asax&lt;/code&gt; or more preferably in your &lt;a href="http://weblogs.asp.net/rashid/archive/2009/02/17/use-bootstrapper-in-your-asp-net-mvc-application-and-reduce-code-smell.aspx" target="_blank"&gt;Bootstrapper&lt;/a&gt;.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6e43e376-0cd1-4fdc-8464-1f2be796f510" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public void ConfigureRESTify()
{
    RESTifySettings.Current
                   .SetCommandFactory(type =&amp;gt; ServiceLocator.Current.GetInstance(type) as IRESTifyCommand)
                   .RegisterCommands();
}

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);

    ConfigureServiceLocator();
    ConfigureRESTify();
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We are setting the factory method which you have seen in the &lt;code&gt;CommandBinder&lt;/code&gt; in the above in the &lt;code&gt;SetCommandFactory&lt;/code&gt;, I usually prefer to abstract the underlying IoC/DI with the CommonServiceLocator, if you do not like it, you use your preferred DI directly over here. Next, we are registering all Commands with our &lt;code&gt;CommandBinder&lt;/code&gt; by scanning the referenced assemblies, if you do not like to scan you can use the overloaded version which accepts specific types or single assembly.&lt;/p&gt;

&lt;p&gt;Now let me answer some of the common questions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I redirect to a action after the command executes, for example, in a CRUD operation when an object is created I want to redirect back to Index for the Html and for the others formats I just want to return the data.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A: &lt;/strong&gt;There are few overloaded methods in the Command which you can use to redirect to other actions for a special format after the command executes. For example, in the above &lt;code&gt;ProductController&lt;/code&gt;’s &lt;code&gt;Create&lt;/code&gt; you can use the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:3a4b0f6f-a981-4ff2-aba7-0b1bb568985a" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(ProductCreateCommand command)
{
    return command.ExecuteAndRedirectToAction("Index").WhenFormatIsHtml();
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;WhenFormatIsHtml&lt;/code&gt; is an extension methods there are other versions of it. Don’t worry about the validation it will not redirect if the validation fails &lt;code&gt;(ModelState.IsValid == false)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What about the other facilities that we often gets in the regular Controllers like Try/UpdateModel, UrlHelper etc etc.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; Most of the facilities that are available in Controller is also available in Command but it does not includes those which are contradictory (methods that returns &lt;code&gt;ActionResult&lt;/code&gt; (w/o redirecting) are excluded). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Looks like the Command object itself inherited from Controller.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; No, it is not. This is the declaration:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:16c072a9-5fda-4d5c-8279-eca3d1b651c2" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public abstract class RESTifyCommand : IRESTifyCommand, IHideObjectMembers&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I on/off supported format?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; To on/off supported formats globally use the &lt;code&gt;RESTifySettings&lt;/code&gt; like the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:2f4f3049-4ec3-4ecb-a55f-1a079c9b4b34" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;RESTifySettings.Current
               .SetCommandDefaultFormats(RESTifyFormats.Html | RESTifyFormats.Json);&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now all your command will only support html and json or you can override the &lt;code&gt;SupportedFormats&lt;/code&gt; property if you want to set it for a specific command, for example, now the &lt;code&gt;ProductListCommand&lt;/code&gt; will only support Html and ATOM: &lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:5b9c39db-3e37-41b0-99de-0ffce3b786f2" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class ProductListCommand : RESTifyCommand
{
    protected override RESTifyFormats SupportedFormats
    {
        get
        {
            return RESTifyFormats.Html | RESTifyFormats.Atom;
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I register custom Result Formatter?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A: To register a formatter that will be applied to all, use the &lt;code&gt;RegisterResultFormatter&lt;/code&gt; method, there is also Command specific version which will set the formatter for only that Command.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How does the Serialization works?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; Well when it comes to serialization in .NET Framework, we have two sets of serializers the regular serializers like XmlSerializer/JavaScriptSerializer and the new DataContractSerializers, but none of it can serve our purpose. For example, DataContractSerializers can only work when the serialized object is decorated with its required attributes, which means you cannot serialize anonymous objects or the objects that are beyond your control also if your object is buildup with other objects it requires to know those other objects. There are also issues with regular serializers. So instead of supporting only a single set, we are supporting both. When serializing we are first first checking whether the object is a known type to us, if it is a known type we use the DataContractSerializers if not we are using the regular serializers. By known type, I mean an object is decorated with DataContractSerializers attributes and it is registered to this extension. To register known types, you can use the &lt;code&gt;RegisterKnownTypes&lt;/code&gt; method of &lt;code&gt;RESTifySettings&lt;/code&gt;, it has similar overloaded versions of &lt;code&gt;RegisterCommands&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How can I play with it, where is the source code located?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A: &lt;/strong&gt;You can check the &lt;a href="http://216.177.71.90/RESTify/Product" target="_blank"&gt;live version&lt;/a&gt; over here or if you want to get the source, checkout my first &lt;a href="http://github.com/kazimanzurrashid/RESTify/tree/master" target="_blank"&gt;open source project in GitHub&lt;/a&gt;.&lt;/p&gt;
That’s it for the day. &lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f08%2f25%2frestify-extending-asp-net-mvc.aspx&amp;amp;title=RESTify+%e2%80%93+Extending+ASP.NET+MVC"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/08/25/restify-extending-asp-net-mvc.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7180605" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/2XSNTf1RzHg" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Patterns/default.aspx">Patterns</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Open+Source/default.aspx">Open Source</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/08/25/restify-extending-asp-net-mvc.aspx</feedburner:origLink></item><item><title>Introducing Telerik Extensions for ASP.NET MVC</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/yzxF92v4Mw0/introducing-telerik-extensions-for-asp-net-mvc.aspx</link><pubDate>Wed, 12 Aug 2009 06:49:14 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7167189</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>22</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7167189</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7167189</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/08/12/introducing-telerik-extensions-for-asp-net-mvc.aspx#comments</comments><description>&lt;p&gt;&lt;strong&gt;[Update: We have just upload the source code in CodePlex. Check it out.]      &lt;br /&gt;&lt;strong&gt;[Update: &lt;/strong&gt;Also checkout the &lt;a href="http://blogs.telerik.com/blogs/posts/09-08-12/announcing_a_new_product_line_-_telerik_extensions_for_asp_net_mvc.aspx" target="_blank"&gt;Atanas post&lt;/a&gt; where he detailed our plans and goals of this product.] &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Today, we have released our first public community technology preview of our ASP.NET MVC Extensions. This is a very lightweight framework for developing ASP.NET MVC View Components that we are working for last few months. There are few key points that I like to mention:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;It is Open Source (dual licensed), yes you heard me. It is the first Open Source project of Telerik released under MS-PL. &lt;/li&gt;    &lt;li&gt;It is free for the time being we will be developing our commercial components based upon this tiny framework. &lt;/li&gt;    &lt;li&gt;It is based upon jQuery, yes we know how much the community loves it. &lt;/li&gt;    &lt;li&gt;It supports multiple view engines. The sample contains the Webform, &lt;a href="http://sparkviewengine.com/" target="_blank"&gt;Spark&lt;/a&gt; and &lt;a href="http://code.google.com/p/nhaml/" target="_blank"&gt;NHaml&lt;/a&gt; examples. &lt;/li&gt;    &lt;li&gt;The CTP contains the popular jQueryUI components as a proof of concepts but you can use it in your application with complete confidence. Since, we will be releasing our own version, it would be difficult for us to give it the same priority, instead we expect the open source community will be responsible for its further development(enhancing, bug fixing and adding new components) and we will be accepting patch/new components for the jQuery components from the community. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;You can download it with complete source/tests/samples/docs from our &lt;a href="http://www.telerik.com/products/aspnet-mvc.aspx" target="_blank"&gt;ASP.NET MVC Product page&lt;/a&gt; &lt;del&gt;(we will be also uploading it in CodePlex), please check back if the page is still not available.&lt;/del&gt; &lt;/p&gt;  &lt;p&gt;You can also check the jQueryUI Webform demo &lt;a href="http://demos.telerik.com/aspnet-mvc/" target="_blank"&gt;over here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;I will be blogging more about this very soon.&lt;/p&gt;  &lt;p&gt;Stay tuned!!!&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f08%2f12%2fintroducing-telerik-extensions-for-asp-net-mvc.aspx&amp;amp;title=Introducing+Telerik+Extensions+for+ASP.NET+MVC"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/08/12/introducing-telerik-extensions-for-asp-net-mvc.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7167189" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/yzxF92v4Mw0" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/jQuery+UI/default.aspx">jQuery UI</category><category domain="http://weblogs.asp.net/rashid/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://weblogs.asp.net/rashid/archive/tags/Telerik/default.aspx">Telerik</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/08/12/introducing-telerik-extensions-for-asp-net-mvc.aspx</feedburner:origLink></item><item><title>JavaScript File Management</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/-gtxURHAOVo/javascript-file-management.aspx</link><pubDate>Fri, 24 Jul 2009 19:54:59 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7154136</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>16</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7154136</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7154136</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/07/25/javascript-file-management.aspx#comments</comments><description>&lt;p&gt;As many of you know that I am currently involved in developing &lt;a href="http://weblogs.asp.net/rashid/archive/2009/05/28/asp-net-mvc-ui-components-continued.aspx" target="_blank"&gt;few UI Components&lt;/a&gt; for the ASP.NET MVC Framework (Hint: It is not a personal project, and we do have the plan to make it &lt;del&gt;the source open&lt;/del&gt; dual license). In this post, I will discuss about our design decisions regarding how we plan to manage the javascript files with our UI Components.&lt;/p&gt;  &lt;p&gt;When developing a typical web application we usually find four kinds of javascript files.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Framework scripts like jQuery, ExtJS or maybe MS Ajax etc. &lt;/li&gt;    &lt;li&gt;UI Component/Plug-in scripts like jQuery UI, jQuery Tools, jQuery validation/forms plug-ins etc that depends upon the framework script. &lt;/li&gt;    &lt;li&gt;Application level common scripts that are shared among multiple pages and might depends upon the above two. &lt;/li&gt;    &lt;li&gt;Page scripts(not embedded in html, rather as external file) that might depends upon on the above three. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;To make the application really responsive/fast we often have to merge/compress/cache these javascript files. Currently most of the framework in .NET world (including the latest ASP.NET AJAX 3.5) supports combining the scripts in a single response. But this is not an optimal option in most of the cases. Why? Because we are either downloading the same file content in different pages or we are downloading some unnecessary file content for a specific page (assuming that you have specified all your merged script in your master page). Certainly it is a one time issue, once the file is downloaded it will be cached and the user does not have to download it again, but does not it also indicate the incapability of your script management components, also this is not viable option in today's heavily ajax sites.. There are also few other considerations like how can I load the scripts from a CDN (free/paid), does it render the scripts at the bottom of the pages etc etc. While considering all the above facts, we think the best way to serve scripts is, if it is merged in groups. Lets consider the following scenario, each url is using the listed javascript files:&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="4"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td&gt;http://mysite.com/List&lt;/td&gt;        &lt;td&gt;http://mysite.com/View/3&lt;/td&gt;        &lt;td&gt;http://mysite.com/Edit/3&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="vertical-align: top"&gt;         &lt;ol&gt;           &lt;li&gt;jquery-1.3.2.js &lt;/li&gt;            &lt;li&gt;jquery-ui-1.7.2.custom.js &lt;/li&gt;            &lt;li&gt;jquery.template.js &lt;/li&gt;            &lt;li&gt;jquery.pagination.js &lt;/li&gt;            &lt;li&gt;Utility.js &lt;/li&gt;            &lt;li&gt;Search.js &lt;/li&gt;            &lt;li&gt;List.js &lt;/li&gt;         &lt;/ol&gt;       &lt;/td&gt;        &lt;td style="vertical-align: top"&gt;         &lt;ol&gt;           &lt;li&gt;jquery-1.3.2.js &lt;/li&gt;            &lt;li&gt;jquery-ui-1.7.2.custom.js &lt;/li&gt;            &lt;li&gt;jquery.template.js &lt;/li&gt;            &lt;li&gt;jquery.pagination.js &lt;/li&gt;            &lt;li&gt;Utility.js &lt;/li&gt;            &lt;li&gt;View.js &lt;/li&gt;         &lt;/ol&gt;       &lt;/td&gt;        &lt;td style="vertical-align: top"&gt;         &lt;ol&gt;           &lt;li&gt;jquery-1.3.2.js &lt;/li&gt;            &lt;li&gt;jquery-ui-1.7.2.custom.js &lt;/li&gt;            &lt;li&gt;jquery.validate.js &lt;/li&gt;            &lt;li&gt;jquery.form.js &lt;/li&gt;            &lt;li&gt;jquery.watermark.js &lt;/li&gt;            &lt;li&gt;Utility.js &lt;/li&gt;            &lt;li&gt;Edit.js &lt;/li&gt;         &lt;/ol&gt;       &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;We can group the above scripts, in the following groups: &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;jQueryBase&lt;/strong&gt;: jquery-1.3.2.js, jquery-ui 1.7.2.custom.js. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;ListView&lt;/strong&gt;: jquery.template.js,jquery.pagination.js. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Form&lt;/strong&gt;: jquery.validate.js,&amp;#160; jquery.form.js, jquery.watermark.js. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;ListLocal&lt;/strong&gt;: Utility.js, Search.js, List.js. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;ViewLocal&lt;/strong&gt;: Utility.js, View.js. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;EditLocal&lt;/strong&gt;: Utility.js, Edit.js. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Now, we can replace with the following:&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="4"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td&gt;http://mysite.com/List&lt;/td&gt;        &lt;td&gt;http://mysite.com/View/3&lt;/td&gt;        &lt;td&gt;http://mysite.com/Edit/3&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="vertical-align: top"&gt;         &lt;ol&gt;           &lt;li&gt;jQueryBase &lt;/li&gt;            &lt;li&gt;ListView &lt;/li&gt;            &lt;li&gt;ListLocal &lt;/li&gt;         &lt;/ol&gt;       &lt;/td&gt;        &lt;td style="vertical-align: top"&gt;         &lt;ol&gt;           &lt;li&gt;jQueryBase &lt;/li&gt;            &lt;li&gt;ListView &lt;/li&gt;            &lt;li&gt;ViewLocal &lt;/li&gt;         &lt;/ol&gt;       &lt;/td&gt;        &lt;td style="vertical-align: top"&gt;         &lt;ol&gt;           &lt;li&gt;jQueryBase &lt;/li&gt;            &lt;li&gt;Form &lt;/li&gt;            &lt;li&gt;EditLocal &lt;/li&gt;         &lt;/ol&gt;       &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;The benefits of the above comparing to individual file or single file combining are:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;We are sending less request to our web server (as the files are now grouped). &lt;/li&gt;    &lt;li&gt;We are not downloading the same file between the page visits (comparing to single file response). &lt;/li&gt;    &lt;li&gt;We are downloading the files that are only required for that visiting page. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;With our Script Management Component it becomes really easy to achieve the above, for example, for the List you can use the following syntax:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:b3542727-0887-4156-b5a8-ce5a39c9b12e" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.jQuery().ScriptRegistrar().Scripts(script =&amp;gt; script.AddGroup( "jqueryBase",
                                                                        group =&amp;gt; group.Add("~/Scripts/jquery-1.3.2.js")
                                                                                      .Add("~/Scripts/jquery-ui-1.7.2.custom.js")
                                                                  )

                                                            .AddGroup( "ListView",
                                                                        group =&amp;gt; group.Add("~/Scripts/jquery.template.js")
                                                                                      .Add("~/Scripts/jquery.pagination.js")
                                                                  )

                                                            .AddGroup("ListLocal",
                                                                        group =&amp;gt; group.Add("~/Scripts/Utility.js")
                                                                                      .Add("~/Scripts/Search.js")
                                                                                      .Add("~/Scripts/List.js")
                                                                  )
                                        )
                                .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;to configure each group setting you can use:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:5a218469-41c9-493d-8f76-6eee55af80dc" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;group =&amp;gt; group.Add("~/Scripts/jquery-1.3.2.js")
              .Add("~/Scripts/jquery-ui-1.7.2.custom.js")
              .Version("2.1)
              .Compress(true)
              .CacheDurationInDays(365)
              .Combined(true)&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;you can also use a CDN instead of loading the each group, it becomes really handy when your application becomes popular, to set the CDN you can use:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:01dbbb88-16bb-428c-aa5d-688e2a25bb3c" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;group =&amp;gt; group.UseContentDeliveryNetwork(true)
              .ContentDeliveryNetworkPath("http//mycdn.com/myScriptGroup.js")&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you do not want to specify the same setting for each group again and again (DRY) you can set the default settings in the application start (global.asax) like the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:23ca6d60-1902-44d9-8bca-44a97da800d0" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);

    WebAssetDefaultSettings.CacheDurationInDays = 365;
    WebAssetDefaultSettings.Combined = true;
    WebAssetDefaultSettings.Compress = true;
    WebAssetDefaultSettings.Version = "2.1";
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When you run the application and open the Firebug, you will find that each group is merged/compressed/cached like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/FB_3BAEB3CD.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="FB" border="0" alt="FB" src="http://weblogs.asp.net/blogs/rashid/FB_thumb_74B56B02.png" width="925" height="378" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;We have included some default behavior (AKA convention over configuration) backed into the script management components, for example when you are running the application in development mode (debug=&amp;quot;true&amp;quot; in web.config) it will include the .debug.js and in release (debug=&amp;quot;false&amp;quot;) .min.js files no matter what filename you have mentioned in the ScriptRegistrar. If the file does not exist (.min.js/.debug.js) it will automatically fallback to the original value. When developing these components we take the YSlow rules very seriously, for example, when you use the ScriptRegistrar, it will render the script tags at bottom of the page, no matter how many ScriptRegistrar placed in the Master/Content/User Controls. Other than script files, you can also mention your startup and cleanup javascript statements in the ScriptRegistrar. For example, if you have the following:&lt;/p&gt;

&lt;p&gt;In Master page:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:a67725f6-fe43-48e8-87ae-a5d15e6ac1a9" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.jQuery().ScriptRegistrar().Scripts(script =&amp;gt; script.AddGroup( "jqueryBase",
                                                                        group =&amp;gt; group.Add("~/Scripts/jquery-1.3.2.js")
                                                                                      .Add("~/Scripts/jquery-ui-1.7.2.custom.js")
                                                                      )
                                            )
                                    .OnPageLoad(() =&amp;gt;
                                                {%&amp;gt;
                                                    test1.init();
                                                &amp;lt;%}
                                               )
                                    .OnPageUnload(() =&amp;gt;
                                                  {%&amp;gt;
                                                      test1.dispose();
                                                  &amp;lt;%}
                                                 )
                                .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and in Content Page:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:45f09b58-5bd8-4569-ae74-4551386e06d9" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.jQuery().ScriptRegistrar().OnPageLoad(() =&amp;gt;
                                                {%&amp;gt;
                                                    test2.init();
                                                &amp;lt;%}
                                               )
                                    .OnPageUnload(() =&amp;gt;
                                                  {%&amp;gt;
                                                      test2.dispose();
                                                  &amp;lt;%}
                                                 ); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and in User Control:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:4b9b6cfc-560f-4696-9046-fa652bc7b362" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.jQuery().ScriptRegistrar().OnPageLoad(() =&amp;gt;
                                                {%&amp;gt;
                                                    test3.init();
                                                &amp;lt;%}
                                               )
                                    .OnPageUnload(() =&amp;gt;
                                                  {%&amp;gt;
                                                      test3.dispose();
                                                  &amp;lt;%}
                                                 ); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When the page renders, it will write the following:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6670d341-7ec1-4f1f-97db-0112722d5419" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;script type="text/javascript" src="http://weblogs.asp.net/asset.axd?id=eyJjdCI6ImJuIjoic2hCcnVzaFhtbC5qcyJ9XX1dfQ%3d%3d"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type="text/javascript"&amp;gt; 
//&amp;lt;![CDATA[
jQuery(document).ready(function(){
test1.init();
test2.init();
test3.init();
});
jQuery(window).unload(function(){
test3.dispose();
test2.dispose();
test1.dispose();
});
//]]&amp;gt;
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There should be a little difference in the Content and User Control code. There will no &lt;code&gt;Render()&lt;/code&gt; for those two. Only the Master will have the &lt;code&gt;Render()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;And it is View Engine independent, we have already tested it in Webforms, Spark and NHaml.&lt;/p&gt;

&lt;p&gt;What do you think? What features it is currently missing? Comments and suggestions are really appreciated.&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f07%2f25%2fjavascript-file-management.aspx&amp;amp;title=JavaScript+File+Management"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/07/25/javascript-file-management.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7154136" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/-gtxURHAOVo" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/jQuery+UI/default.aspx">jQuery UI</category><category domain="http://weblogs.asp.net/rashid/archive/tags/jQuery/default.aspx">jQuery</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/07/25/javascript-file-management.aspx</feedburner:origLink></item><item><title>ASP.NET MVC UI Components (Continued)</title><link>http://feedproxy.google.com/~r/kazimanzurrashid/~3/p_wxE9ABe9Y/asp-net-mvc-ui-components-continued.aspx</link><pubDate>Thu, 28 May 2009 15:44:51 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7100453</guid><dc:creator>kazimanzurrashid</dc:creator><slash:comments>16</slash:comments><wfw:commentRss>http://weblogs.asp.net/rashid/rsscomments.aspx?PostID=7100453</wfw:commentRss><wfw:comment>http://weblogs.asp.net/rashid/commentapi.aspx?PostID=7100453</wfw:comment><comments>http://weblogs.asp.net/rashid/archive/2009/05/28/asp-net-mvc-ui-components-continued.aspx#comments</comments><description>&lt;p&gt;In my &lt;a href="http://weblogs.asp.net/rashid/archive/2009/05/20/asp-net-mvc-poll-result-jquery-ui-mvc-component-demo-and-more-feedback-required.aspx" target="_blank"&gt;last post&lt;/a&gt;, two important issues are raised&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The justification of having server side components for &lt;a href="http://ui.jquery.com" target="_blank"&gt;jQuery UI&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;The style of syntax. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;The intension of my last post was to get the feedback of the type of syntax the ASP.NET MVC developer prefers, so I did not mention anything on the server side side integration, this might be the reason why few people were unable to find the benefits of this server side support. In this post, I will try to show few simple examples of the server side integration, lets say that you are creating a Task submit form, you can use the Slider as completed percent field instead of regular input field, like the following:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;View:&lt;/strong&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:048b962f-4b25-47a7-b055-1b60666912e0" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage&amp;lt;Task&amp;gt;" %&amp;gt;
&amp;lt;asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"&amp;gt;
    Slider Value Form Submit Example
&amp;lt;/asp:Content&amp;gt;
&amp;lt;asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"&amp;gt;
    &amp;lt;% using(Html.BeginForm()){%&amp;gt;
        &amp;lt;fieldset&amp;gt;
            &amp;lt;legend&amp;gt;Submit Task&amp;lt;/legend&amp;gt;
            &amp;lt;span style="color:Blue;font-weight:bold"&amp;gt;
                &amp;lt;%= ViewData.Get&amp;lt;string&amp;gt;("successMessage") %&amp;gt;
            &amp;lt;/span&amp;gt;
            &amp;lt;%= Html.ValidationSummary("Please correct the following errors:") %&amp;gt;
            &amp;lt;div&amp;gt;
                &amp;lt;label for="name"&amp;gt;Name:&amp;lt;/label&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div style="margin-top:5px"&amp;gt;
                &amp;lt;%= Html.TextBox("task.Name", null, new { style = "width:200px" })%&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div style="margin-top:5px"&amp;gt;
                &amp;lt;%= Html.ValidationMessage("task.Name")%&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div style="margin-top:10px"&amp;gt;
                Completed: &amp;lt;span id="completedPercent" style="color:Black"&amp;gt;&amp;lt;/span&amp;gt;%
            &amp;lt;/div&amp;gt;
            &amp;lt;div style="margin-top:5px;width:200px"&amp;gt;
                &amp;lt;% Html.jQuery().Slider()
                                .Name("task.Completed")
                                .UpdateElements("#completedPercent")
                                .Render(); %&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div style="margin-top:5px"&amp;gt;
                &amp;lt;%= Html.ValidationMessage("task.Completed")%&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div style="margin-top:10px"&amp;gt;
                &amp;lt;input type="submit" value="Submit"/&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/fieldset&amp;gt;
    &amp;lt;% }%&amp;gt;
&amp;lt;/asp:Content&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Controller:&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:bfe549d4-611b-4a40-9797-5b6fb4bc4c94" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;[AcceptVerbs(HttpVerbs.Get)]
public ActionResult FormSubmitWithValue()
{
    return View(new Task());
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult FormSubmitWithValue([Bind]Task task)
{
    if (string.IsNullOrEmpty(task.Name))
    {
        ModelState.AddModelError("task.Name", "Name cannot be blank.");
    }

    if (task.Completed &amp;lt;= 0)
    {
        ModelState.AddModelError("task.Completed", "Invalid task complete percent.");
    }

    if (ModelState.IsValid)
    {
        //Save here;
        ViewData.Set("successMessage", "Task saved successfully.");
    }

    return View(task);
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="http://216.177.71.90/jQueryMVC/Slider/FormSubmitWithValue" target="_blank"&gt;[Live Version]&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check that (line 26- 29 in the above View) you are using the same kind of naming as you do in strongly typed view for regular input fields, you can use the slider for non-strongly typed view too.&lt;/p&gt;

&lt;p&gt;In case of Slider is ranged, we can use the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;View:&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:a212b6af-6a67-4362-92e3-e9cd63020f0a" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %&amp;gt;
&amp;lt;asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"&amp;gt;
    Slider Values Form Submit Example
&amp;lt;/asp:Content&amp;gt;
&amp;lt;asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"&amp;gt;
    &amp;lt;% using(Html.BeginForm()){%&amp;gt;
        &amp;lt;fieldset&amp;gt;
            &amp;lt;legend&amp;gt;Submit Department&amp;lt;/legend&amp;gt;
            &amp;lt;span style="color:Blue;font-weight:bold"&amp;gt;
                &amp;lt;%= ViewData.Get&amp;lt;string&amp;gt;("successMessage") %&amp;gt;
            &amp;lt;/span&amp;gt;
            &amp;lt;%= Html.ValidationSummary("Please correct the following errors:") %&amp;gt;
            &amp;lt;div&amp;gt;
                &amp;lt;label for="name"&amp;gt;Name:&amp;lt;/label&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div style="margin-top:5px"&amp;gt;
                &amp;lt;%= Html.TextBox("name", null, new { style = "width:200px" })%&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div style="margin-top:5px"&amp;gt;
                &amp;lt;%= Html.ValidationMessage("name") %&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div style="margin-top:10px"&amp;gt;
                Salary: $&amp;lt;span id="rangeFrom" style="color:Black"&amp;gt;&amp;lt;/span&amp;gt; - $&amp;lt;span id="rangeTo" style="color:Black"&amp;gt;&amp;lt;/span&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div style="margin-top:5px;width:600px"&amp;gt;
                &amp;lt;% Html.jQuery().Slider()
                                .Name("salary")
                                .Range(jQuerySliderRange.True)
                                .Values(1000, 2500)  //Initial value
                                .UpdateElements("#rangeFrom", "#rangeTo")
                                .Minimum(1000)
                                .Maximum(10000)
                                .Steps(500)
                                .Render(); %&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div style="margin-top:5px"&amp;gt;
                &amp;lt;%= Html.ValidationMessage("salary")%&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div style="margin-top:10px"&amp;gt;
                &amp;lt;input type="submit" value="Submit"/&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/fieldset&amp;gt;
    &amp;lt;% }%&amp;gt;
&amp;lt;/asp:Content&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Controller:&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:2acfa18e-8e06-4270-b23e-4e13e99f2724" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;[AcceptVerbs(HttpVerbs.Get)]
public ActionResult FormSubmitWithValues()
{
    return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult FormSubmitWithValues(string name, IList&amp;lt;int&amp;gt; salary)
{
    if (string.IsNullOrEmpty(name))
    {
        ModelState.AddModelError("name", "Name cannot be blank.");
    }

    if (salary.Count != 2)
    {
        ModelState.AddModelError("salary", "Invalid salary range.");
    }

    if (salary.Count == 2)
    {
        if (salary[0] &amp;lt;= 1000)
        {
            ModelState.AddModelError("salary", "Salary minimum range should be greater than 1000.");
        }

        if (salary[1] &amp;lt;= 2500)
        {
            ModelState.AddModelError("salary", "Salary maximum range should be greater than 2500.");
        }
    }

    if (ModelState.IsValid)
    {
        //Save here;
        ViewData.Set("successMessage", "Department saved successfully.");
    }

    return View();
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="http://216.177.71.90/jQueryMVC/Slider/FormSubmitWithValues" target="_blank"&gt;[Live Version]&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the slider is a range slider, it will have an array of values, that is why the controllers accepts &lt;code&gt;IList&amp;lt;int&amp;gt;&lt;/code&gt; for the slider. This will also work for strongly typed view.&lt;/p&gt;

&lt;p&gt;You can also use the ProgressBar to auto retrieve the value directly from ViewData, for example,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;View:&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:a3aedb36-eeb8-4d29-bde4-b206db0d92b0" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %&amp;gt;
&amp;lt;asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"&amp;gt;
    ProgressBar Auto Retrieve Value Example
&amp;lt;/asp:Content&amp;gt;
&amp;lt;asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"&amp;gt;
    &amp;lt;% Html.jQuery().ProgressBar()
                    .Name("myProgressBar")
                    .Render(); %&amp;gt;
&amp;lt;/asp:Content&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Controller:&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:fa255e99-0606-40d6-b53d-63c2671c61e5" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public ActionResult AutoRetrieve()
{
    ViewData["myProgressBar"] = 40;

    return View();
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="http://216.177.71.90/jQueryMVC/ProgressBar/AutoRetrieve" target="_blank"&gt;[Live Version]&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;As mentioned &lt;a href="http://weblogs.asp.net/rashid/archive/2009/05/07/asp-net-mvc-poll-time.aspx" target="_blank"&gt;in the past&lt;/a&gt; that the goal of this component is to add some RAD support for the ASP.NET MVC Developers. For example, in the original jQuery UI both Slider and ProgressBar does not have any built-in support to show the value(s) in an associated html element(s), but it does have this support to attach any html elements to show the numeric value(s), check the &lt;code&gt;UpdateElements&lt;/code&gt; method in the above (works on jQuery Selector), behind the scene it generates the necessary javascript codes to hook the events and update the elements, the same is true for the above slider form submit examples, it generates the required hidden input(s) to support form submit. It will not discourage you from writing javascript codes, instead it automates some common repetitive tasks. The next thing of my previous blog post was the benefits of server side generating the necessary html and javascript codes even when there is no integration of server side like the above slider or progressbar, to demonstrate it, I will first create a dynamic jQuery UI tab with raw html and javascripts, lets assume the tab items are disabled and selected based upon some condition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Raw Html and JavaScript:&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:a79bcf7a-1f26-478f-a819-0a61b8d4cb83" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage&amp;lt;IList&amp;lt;DynamicTabContent&amp;gt;&amp;gt;" %&amp;gt;
&amp;lt;asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"&amp;gt;
    Tab Dynamic Item Example
&amp;lt;/asp:Content&amp;gt;
&amp;lt;asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"&amp;gt;
    &amp;lt;% var disabledIndexes = new List&amp;lt;string&amp;gt;(); %&amp;gt;
    &amp;lt;% var selectedIndex = 0; %&amp;gt;
    &amp;lt;div id="tabs"&amp;gt;
        &amp;lt;ul&amp;gt;
            &amp;lt;% for (var i = 0; i &amp;lt; Model.Count; i++) {%&amp;gt;
                &amp;lt;li&amp;gt;&amp;lt;a href="#section-&amp;lt;%= i %&amp;gt;"&amp;gt;&amp;lt;%= Html.Encode(Model[i].Header)%&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;% }%&amp;gt;
        &amp;lt;/ul&amp;gt;
        &amp;lt;% for (var i = 0; i &amp;lt; Model.Count; i++) {%&amp;gt;
            &amp;lt;% var dynamicContent = Model[i]; %&amp;gt;
            &amp;lt;div id="section-&amp;lt;%= i %&amp;gt;"&amp;gt;
                &amp;lt;p&amp;gt;&amp;lt;%= Html.Encode(dynamicContent.Content) %&amp;gt;&amp;lt;/p&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;% if (dynamicContent.IsDisabled)
               {
                   disabledIndexes.Add(i.ToString());
               }
               //The last selected will win
               if (dynamicContent.IsSelected &amp;amp;&amp;amp; (i &amp;gt; selectedIndex))
               {
                   selectedIndex = i;
               }
            %&amp;gt;
        &amp;lt;% }%&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;script type="text/javascript"&amp;gt;
        $(document).ready(function(){
            $('#tabs').tabs({
                                selected : &amp;lt;%= selectedIndex %&amp;gt;,
                                disabled : [&amp;lt;%= string.Join(", ", disabledIndexes.ToArray()) %&amp;gt;]
                            });
        });
    &amp;lt;/script&amp;gt;
&amp;lt;/asp:Content&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the above, we are first iterating the Model to generate the tab headers, next we are again iterating it to generate the content panes and this time we are also populating the disabled index list and selecting the selected index. At last, we are dumping the selected index and converting the disabled indexes to a comma delimited string to create the tab in javascript.&lt;/p&gt;

&lt;p&gt;Now lets see how this can simplify the above situation, we can do the exact same thing with the following codes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple Fluent:&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:44fd2d7d-2bf2-4220-9fff-455a8f33b695" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage&amp;lt;IList&amp;lt;DynamicTabContent&amp;gt;&amp;gt;" %&amp;gt;
&amp;lt;asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"&amp;gt;
    Tab Dynamic Item Example
&amp;lt;/asp:Content&amp;gt;
&amp;lt;asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"&amp;gt;
    &amp;lt;% Html.jQuery().Tab().Name("tabs")
                          .Items(item =&amp;gt;
                                         {
                                             for(var i = 0; i &amp;lt; Model.Count; i++)
                                             {
                                                 var dynamicContent = Model[i];

                                                 item.Create()
                                                     .HeaderText(dynamicContent.Header)
                                                     .Content(() =&amp;gt;
                                                                      {%&amp;gt;
                                                                        &amp;lt;p&amp;gt;&amp;lt;%= Html.Encode(dynamicContent.Content) %&amp;gt;&amp;lt;/p&amp;gt;
                                                                      &amp;lt;%}
                                                             )
                                                     .Selected(dynamicContent.IsSelected)
                                                     .Disabled(dynamicContent.IsDisabled);
                                             }
                                         }
                                )
                          .Render(); %&amp;gt;
&amp;lt;/asp:Content&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="http://216.177.71.90/jQueryMVC/ProgressBar/AutoRetrieve" target="_blank"&gt;[Live Version]&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see it is much more simpler and concise and with the above, we do not have to iterate the model again and again, no need to maintain the selected index and disabled index list, the component takes these responsibility and generates the Tab. I hope this clarifies the issue.&lt;/p&gt;

&lt;p&gt;The second issue is the style of syntax, first, let me post the result of my &lt;a href="http://twtpoll.com/8me8cs" target="_blank"&gt;previous Poll&lt;/a&gt; (total 48 votes):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Regular Methods (9 votes, 19%) &lt;/li&gt;

  &lt;li&gt;Simple Fluent (14 votes, 29%) &lt;/li&gt;

  &lt;li&gt;Progressive Fluent(25 votes, 52%) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Though the progressive has more votes, but I think once you are familiar with the syntax, the verboseness of the progressive fluent will start to irritate you and this is the reason why I have changed it to simple fluent from progressive fluent. You can download the latest version from the bottom of the post. Another interesting syntax proposed my &lt;a href="http://www.lostechies.com/blogs/chad_myers/" target="_blank"&gt;Chad Myer&lt;/a&gt;. The difference between mine with this is that it first creates the component, but instead of returning the component it provides an &lt;code&gt;Action&lt;/code&gt; to configure the component. Let us do a side by side comparison of this syntax with the simple fluent, here we will see the basic tab:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Factory + Action Syntax:&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9ea15a4c-4b9d-48b6-91ec-4c4405f61e8e" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.jQuery&amp;lt;jQueryTab&amp;gt;(tab =&amp;gt;
                                       {
                                           tab.Name = "myTab";
                                           tab.Items(items =&amp;gt;
                                                             {
                                                                 items.Create(item =&amp;gt;
                                                                                        {
                                                                                            item.HeaderText = "Nunc tincidunt";
                                                                                            item.Content = () =&amp;gt;
                                                                                                                {%&amp;gt;
                                                                                                                     &amp;lt;p&amp;gt;
                                                                                                                         Proin elit arcu, rutrum commodo, vehicula tempus,
                                                                                                                         commodo a, risus. Curabitur nec arcu. Donec
                                                                                                                         sollicitudin mi sit amet mauris. Nam elementum
                                                                                                                         quam ullamcorper ante. Etiam aliquet massa et
                                                                                                                         lorem. Mauris dapibus lacus auctor risus. Aenean
                                                                                                                         tempor ullamcorper leo. Vivamus sed magna quis
                                                                                                                         ligula eleifend adipiscing. Duis orci. Aliquam
                                                                                                                         sodales tortor vitae ipsum. Aliquam nulla. Duis
                                                                                                                         aliquam molestie erat. Ut et mauris vel pede
                                                                                                                         varius sollicitudin. Sed ut dolor nec orci
                                                                                                                         tincidunt interdum. Phasellus ipsum. Nunc
                                                                                                                         tristique tempus lectus.
                                                                                                                    &amp;lt;/p&amp;gt;
                                                                                                                 &amp;lt;%};
                                                                                        }
                                                                               );

                                                                 items.Create(item =&amp;gt;
                                                                                        {
                                                                                            item.HeaderText = "Proin dolor";
                                                                                            item.Content = () =&amp;gt;
                                                                                                                {%&amp;gt;
                                                                                                                     &amp;lt;p&amp;gt;
                                                                                                                        Morbi tincidunt, dui sit amet facilisis feugiat,
                                                                                                                        odio metus gravida ante, ut pharetra massa metus
                                                                                                                        id nunc. Duis scelerisque molestie turpis. Sed
                                                                                                                        fringilla, massa eget luctus malesuada, metus eros
                                                                                                                        molestie lectus, ut tempus eros massa ut dolor.
                                                                                                                        Aenean aliquet fringilla sem. Suspendisse sed
                                                                                                                        ligula in ligula suscipit aliquam. Praesent in
                                                                                                                        eros vestibulum mi adipiscing adipiscing. Morbi
                                                                                                                        facilisis. Curabitur ornare consequat nunc. Aenean
                                                                                                                        vel metus. Ut posuere viverra nulla. Aliquam erat
                                                                                                                        volutpat. Pellentesque convallis. Maecenas feugiat,
                                                                                                                        tellus pellentesque pretium posuere, felis lorem
                                                                                                                        euismod felis, eu ornare leo nisi vel felis.
                                                                                                                        Mauris consectetur tortor et purus.
                                                                                                                    &amp;lt;/p&amp;gt;
                                                                                                                 &amp;lt;%};
                                                                                        }
                                                                               );

                                                                 items.Create(item =&amp;gt;
                                                                                        {
                                                                                            item.HeaderText = "Aenean lacinia";
                                                                                            item.Content = () =&amp;gt;
                                                                                                                {%&amp;gt;
                                                                                                                    &amp;lt;p&amp;gt;
                                                                                                                        Mauris eleifend est et turpis. Duis id erat.
                                                                                                                        Suspendisse potenti. Aliquam vulputate, pede vel
                                                                                                                        vehicula accumsan, mi neque rutrum erat, eu congue
                                                                                                                        orci lorem eget lorem. Vestibulum non ante. Class
                                                                                                                        aptent taciti sociosqu ad litora torquent per
                                                                                                                        conubia nostra, per inceptos himenaeos. Fusce
                                                                                                                        sodales. Quisque eu urna vel enim commodo
                                                                                                                        pellentesque. Praesent eu risus hendrerit ligula
                                                                                                                        tempus pretium. Curabitur lorem enim, pretium nec,
                                                                                                                        feugiat nec, luctus a, lacus.
                                                                                                                    &amp;lt;/p&amp;gt;
                                                                                                                    &amp;lt;p&amp;gt;
                                                                                                                        Duis cursus. Maecenas ligula eros, blandit nec,
                                                                                                                        pharetra at, semper at, magna. Nullam ac lacus.
                                                                                                                        Nulla facilisi. Praesent viverra justo vitae neque.
                                                                                                                        Praesent blandit adipiscing velit. Suspendisse
                                                                                                                        potenti. Donec mattis, pede vel pharetra blandit,
                                                                                                                        magna ligula faucibus eros, id euismod lacus dolor
                                                                                                                        eget odio. Nam scelerisque. Donec non libero sed
                                                                                                                        nulla mattis commodo. Ut sagittis. Donec nisi
                                                                                                                        lectus, feugiat porttitor, tempor ac, tempor vitae,
                                                                                                                        pede. Aenean vehicula velit eu tellus interdum
                                                                                                                        rutrum. Maecenas commodo. Pellentesque nec elit.
                                                                                                                        Fusce in lacus. Vivamus a libero vitae lectus
                                                                                                                        hendrerit hendrerit.
                                                                                                                    &amp;lt;/p&amp;gt;
                                                                                                                 &amp;lt;%};
                                                                                        }
                                                                               );
                                                             }
                                                    );
                                       }
                            ); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple Fluent:&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:e75900e8-2c7a-4e91-8841-e80bd1c670d0" class="wlWriterSmartContent"&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;% Html.jQuery().Tab()
                .Name("myTab")
                .Items(items =&amp;gt;
                              {
                                 items.Create()
                                      .HeaderText("Nunc tincidunt")
                                      .Content(() =&amp;gt;
                                                     {%&amp;gt;
                                                         &amp;lt;p&amp;gt;
                                                             Proin elit arcu, rutrum commodo, vehicula tempus,
                                                             commodo a, risus. Curabitur nec arcu. Donec
                                                             sollicitudin mi sit amet mauris. Nam elementum
                                                             quam ullamcorper ante. Etiam aliquet massa et
                                                             lorem. Mauris dapibus lacus auctor risus. Aenean
                                                             tempor ullamcorper leo. Vivamus sed magna quis
                                                             ligula eleifend adipiscing. Duis orci. Aliquam
                                                             sodales tortor vitae ipsum. Aliquam nulla. Duis
                                                             aliquam molestie erat. Ut et mauris vel pede
                                                             varius sollicitudin. Sed ut dolor nec orci
                                                             tincidunt interdum. Phasellus ipsum. Nunc
                                                             tristique tempus lectus.
                                                        &amp;lt;/p&amp;gt;
                                                     &amp;lt;%}
                                                );

                                  items.Create()
                                       .HeaderText("Proin dolor")
                                       .Content(() =&amp;gt;
                                                     {%&amp;gt;
                                                         &amp;lt;p&amp;gt;
                                                            Morbi tincidunt, dui sit amet facilisis feugiat,
                                                            odio metus gravida ante, ut pharetra massa metus
                                                            id nunc. Duis scelerisque molestie turpis. Sed
                                                            fringilla, massa eget luctus malesuada, metus eros
                                                            molestie lectus, ut tempus eros massa ut dolor.
                                                            Aenean aliquet fringilla sem. Suspendisse sed
                                                            ligula in ligula suscipit aliquam. Praesent in
                                                            eros vestibulum mi adipiscing adipiscing. Morbi
                                                            facilisis. Curabitur ornare consequat nunc. Aenean
                                                            vel metus. Ut posuere viverra nulla. Aliquam erat
                                                            volutpat. Pellentesque convallis. Maecenas feugiat,
                                                            tellus pellentesque pretium posuere, felis lorem
                                                            euismod felis, eu ornare leo nisi vel felis.
                                                            Mauris consectetur tortor et purus.
                                                        &amp;lt;/p&amp;gt;
                                                     &amp;lt;%}
                                                );

                                  items.Create()
                                       .HeaderText("Aenean lacinia")
                                       .Content(() =&amp;gt;
                                                     {%&amp;gt;
                                                        &amp;lt;p&amp;gt;
                                                            Mauris eleifend est et turpis. Duis id erat.
                                                            Suspendisse potenti. Aliquam vulputate, pede vel
                                                            vehicula accumsan, mi neque rutrum erat, eu congue
                                                            orci lorem eget lorem. Vestibulum non ante. Class
                                                            aptent taciti sociosqu ad litora torquent per
                                                            conubia nostra, per inceptos himenaeos. Fusce
                                                            sodales. Quisque eu urna vel enim commodo
                                                            pellentesque. Praesent eu risus hendrerit ligula
                                                            tempus pretium. Curabitur lorem enim, pretium nec,
                                                            feugiat nec, luctus a, lacus.
                                                        &amp;lt;/p&amp;gt;
                                                        &amp;lt;p&amp;gt;
                                                            Duis cursus. Maecenas ligula eros, blandit nec,
                                                            pharetra at, semper at, magna. Nullam ac lacus.
                                                            Nulla facilisi. Praesent viverra justo vitae neque.
                                                            Praesent blandit adipiscing velit. Suspendisse
                                                            potenti. Donec mattis, pede vel pharetra blandit,
                                                            magna ligula faucibus eros, id euismod lacus dolor
                                                            eget odio. Nam scelerisque. Donec non libero sed
                                                            nulla mattis commodo. Ut sagittis. Donec nisi
                                                            lectus, feugiat porttitor, tempor ac, tempor vitae,
                                                            pede. Aenean vehicula velit eu tellus interdum
                                                            rutrum. Maecenas commodo. Pellentesque nec elit.
                                                            Fusce in lacus. Vivamus a libero vitae lectus
                                                            hendrerit hendrerit.
                                                        &amp;lt;/p&amp;gt;
                                                     &amp;lt;%}
                                                );
                              }
                       )
                .Render(); %&amp;gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To me the simple fluent is much simpler than Chad’s Factory + Action. But I think, it completely depends upon the personal preference. If you think, Factory + Action is much preferable than the simple fluent or even you want to revert back to the initial progressive fluent, do let me know I will change it&amp;#160; based upon your feedback.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://216.177.71.90/jQueryMVC" target="_blank"&gt;[Live Version]&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/rashid/Griffin-090528.zip" target="_blank"&gt;[Download Sample]&lt;/a&gt;&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;div class="shoutIt"&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fweblogs.asp.net%2frashid%2farchive%2f2009%2f05%2f28%2fasp-net-mvc-ui-components-continued.aspx&amp;amp;title=ASP.NET+MVC+UI+Components+(Continued)"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http://weblogs.asp.net/rashid/archive/2009/05/28/asp-net-mvc-ui-components-continued.aspx" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7100453" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/kazimanzurrashid/~4/p_wxE9ABe9Y" height="1" width="1"/&gt;</description><category domain="http://weblogs.asp.net/rashid/archive/tags/Asp.net/default.aspx">Asp.net</category><category domain="http://weblogs.asp.net/rashid/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASPNETMVC/default.aspx">ASPNETMVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://weblogs.asp.net/rashid/archive/tags/jQuery+UI/default.aspx">jQuery UI</category><category domain="http://weblogs.asp.net/rashid/archive/tags/jQuery/default.aspx">jQuery</category><feedburner:origLink>http://weblogs.asp.net/rashid/archive/2009/05/28/asp-net-mvc-ui-components-continued.aspx</feedburner:origLink></item></channel></rss>
