<?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:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-7365737872932202828</atom:id><lastBuildDate>Fri, 24 May 2013 20:24:17 +0000</lastBuildDate><category>xml</category><category>client-side validation</category><category>proxy</category><category>antiforgerytoken</category><category>asynchronous</category><category>authentication</category><category>ajax</category><category>file icons</category><category>sys.services.authenticationservice</category><category>import</category><category>client ip</category><category>cross-origin resource sharing</category><category>tinymce</category><category>transformation</category><category>treeview</category><category>httphandler</category><category>xslt</category><category>range requests</category><category>export</category><category>ajaxcontroltoolkit</category><category>grid</category><category>crud</category><category>jquery ui progressbar</category><category>toolkitscriptmanager</category><category>jquery</category><category>treegrid</category><category>http headers</category><category>jeditable</category><category>configuration</category><category>helper</category><category>subgrid</category><category>jquery ui</category><category>cors</category><category>WebPI</category><category>lib.web.mvc</category><category>file upload</category><category>jquery validation</category><category>asp.net</category><category>jqgrid</category><category>jqueryui dialog</category><category>asp.net mvc</category><title>Yet another developer blog</title><description /><link>http://tpeczek.blogspot.com/</link><managingEditor>noreply@blogger.com (Tomasz Pęczek)</managingEditor><generator>Blogger</generator><openSearch:totalResults>38</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/YetAnotherDeveloperBlog" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="yetanotherdeveloperblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">YetAnotherDeveloperBlog</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://feedburner.google.com</feedburner:feedburnerHostname><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-88786809545834652</guid><pubDate>Mon, 18 Feb 2013 16:00:00 +0000</pubDate><atom:updated>2013-02-18T17:00:52.401+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">jquery</category><category domain="http://www.blogger.com/atom/ns#">helper</category><category domain="http://www.blogger.com/atom/ns#">jqgrid</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><category domain="http://www.blogger.com/atom/ns#">jquery ui</category><title>jqGrid Strongly Typed Helper - jQuery UI Integrations</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;I have released version 6.2.0 of &lt;a href="http://tpeczek.codeplex.com/"&gt;Lib.Web.Mvc&lt;/a&gt; couple days ago and it is available on &lt;a href="http://tpeczek.codeplex.com/releases/view/95990"&gt;CodePlex&lt;/a&gt; or via &lt;em&gt;NuGet&lt;/em&gt;:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" border="0" src="http://3.bp.blogspot.com/-rF_BKvDLaeA/TYJgI6fb7aI/AAAAAAAAANg/xXYpsvT2PP4/s1600/lib-web-mvc-nuget.png" /&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This release brings some updates to &lt;a href="http://tpeczek.blogspot.com/2011/03/jqgrid-and-aspnet-mvc-strongly-typed.html"&gt;jqGrid strongly typed helper&lt;/a&gt; (you can check full list &lt;a href="http://tpeczek.codeplex.com/wikipage?title=Lib.Web.Mvc%20Change%20Log&amp;amp;referringTitle=Documentation"&gt;here&lt;/a&gt;) and I would like to describe closer one of them - &lt;em&gt;jQuery UI&lt;/em&gt; integration features:&lt;ul&gt;&lt;li&gt;JqGridColumnEditTypes.JQueryUIAutocomplete&lt;/li&gt;&lt;li&gt;JqGridColumnSearchTypes.JQueryUIAutocomplete&lt;/li&gt;&lt;li&gt;JqGridColumnEditTypes.JQueryUISpinner&lt;/li&gt;&lt;li&gt;JqGridColumnSearchTypes.JQueryUISpinner&lt;/li&gt;&lt;li&gt;JqGridColumnEditTypes.JQueryUIDatepicker&lt;/li&gt;&lt;li&gt;JqGridColumnSearchTypes.JQueryUIDatepicker&lt;/li&gt;&lt;li&gt;JqGridColumnPredefinedFormatters.JQueryUIButton&lt;/li&gt;&lt;/ul&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;&lt;strong&gt;JQueryUIAutocomplete (JqGridColumnEditTypes/JqGridColumnSearchTypes)&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This is a custom search and edit type which allows easy configuration of &lt;a href="http://jqueryui.com/autocomplete/"&gt;jQuery UI Autocomplete&lt;/a&gt; widget for the column:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" border="0" src="http://1.bp.blogspot.com/-11nChhBuZMQ/ULu6cvjFUFI/AAAAAAAAAQQ/RIKq7Op9lzg/s1600/JQueryUIAutocomplete.png" /&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Widget options are available through &lt;em&gt;JqGridColumnSearchable&lt;/em&gt; and &lt;em&gt;JqGridColumnEditable&lt;/em&gt; attributes properties:&lt;ul&gt;&lt;li&gt;AutoFocus&lt;/li&gt;&lt;li&gt;Delay&lt;/li&gt;&lt;li&gt;MinLength&lt;/li&gt;&lt;/ul&gt;The &lt;em&gt;action&lt;/em&gt; and &lt;em&gt;controller&lt;/em&gt; from which the suggestions will be requested can be set through attributes constructors, while all the events can be bound in standard way - by overriding the &lt;em&gt;DataEvents&lt;/em&gt; property.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;&lt;strong&gt;JQueryUISpinner (JqGridColumnEditTypes/JqGridColumnSearchTypes)&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This is a custom search and edit type which allows easy configuration of &lt;a href="http://jqueryui.com/spinner/"&gt;jQuery UI Spinner&lt;/a&gt; widget for the column:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" border="0" src="http://4.bp.blogspot.com/-eu35pYvgqxE/UOCVvt0rTAI/AAAAAAAAASI/EXVPJNxswsU/s1600/JQueryUISpinner.png" /&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Widget options are also available through &lt;em&gt;JqGridColumnSearchable&lt;/em&gt; and &lt;em&gt;JqGridColumnEditable&lt;/em&gt; attributes properties:&lt;ul&gt;&lt;li&gt;Culture&lt;/li&gt;&lt;li&gt;SpinnerDownIcon&lt;/li&gt;&lt;li&gt;SpinnerUpIcon&lt;/li&gt;&lt;li&gt;Incremental&lt;/li&gt;&lt;li&gt;Max&lt;/li&gt;&lt;li&gt;Min&lt;/li&gt;&lt;li&gt;NumberFormat&lt;/li&gt;&lt;li&gt;Page&lt;/li&gt;&lt;li&gt;Step&lt;/li&gt;&lt;/ul&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;&lt;strong&gt;JQueryUIDatepicker (JqGridColumnEditTypes/JqGridColumnSearchTypes)&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This is a custom search and edit type which allows easy configuration of &lt;a href="http://jqueryui.com/datepicker/"&gt;jQuery UI Datepicker&lt;/a&gt; widget for the column:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" border="0" src="http://2.bp.blogspot.com/-3VssBTwO3MM/URAMEzTo7RI/AAAAAAAAAUs/wGebw3-Bmvg/s1600/JQueryUIDatepicker.png" /&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Following properties of &lt;em&gt;JqGridColumnSearchable&lt;/em&gt; and &lt;em&gt;JqGridColumnEditable&lt;/em&gt; attributes can be used to configure the widget behavior:&lt;ul&gt;&lt;li&gt;AppendText&lt;/li&gt;&lt;li&gt;AutoSize&lt;/li&gt;&lt;li&gt;ChangeMonth&lt;/li&gt;&lt;li&gt;ChangeYear&lt;/li&gt;&lt;li&gt;ConstrainInput&lt;/li&gt;&lt;li&gt;DateFormat&lt;/li&gt;&lt;li&gt;FirstDay&lt;/li&gt;&lt;li&gt;GotoCurrent&lt;/li&gt;&lt;li&gt;MaxDate&lt;/li&gt;&lt;li&gt;MinDate&lt;/li&gt;&lt;li&gt;NumberOfMonths&lt;/li&gt;&lt;li&gt;SelectOtherMonths&lt;/li&gt;&lt;li&gt;ShortYearCutoff&lt;/li&gt;&lt;li&gt;ShowCurrentAtPos&lt;/li&gt;&lt;li&gt;ShowMonthAfterYear&lt;/li&gt;&lt;li&gt;ShowOtherMonths&lt;/li&gt;&lt;li&gt;ShowWeek&lt;/li&gt;&lt;li&gt;StepMonths&lt;/li&gt;&lt;li&gt;YearRange&lt;/li&gt;&lt;li&gt;YearSuffix&lt;/li&gt;&lt;/ul&gt;The widget will take the localization settings (&lt;em&gt;dayNames&lt;/em&gt;, &lt;em&gt;dayNamesMin&lt;/em&gt;, &lt;em&gt;dayNamesShort&lt;/em&gt;, &lt;em&gt;monthNames&lt;/em&gt; and &lt;em&gt;monthNamesShort&lt;/em&gt;) from &lt;em&gt;jqGrid&lt;/em&gt; language settings.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;&lt;strong&gt;JQueryUIButton (JqGridColumnPredefinedFormatters)&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This is a custom formatter which allows easy configuration of &lt;a href="http://jqueryui.com/button/"&gt;jQuery UI Button&lt;/a&gt; widget for the column:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" border="0" src="http://2.bp.blogspot.com/-5U4HVgXCqYs/URujwVQg4LI/AAAAAAAAAVQ/XEL4tm0AZ0k/s1600/JQueryUIButton.png" /&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Widget options are available through &lt;em&gt;JqGridColumnFormatter&lt;/em&gt; attribute properties:&lt;ul&gt;&lt;li&gt;Label&lt;/li&gt;&lt;li&gt;PrimaryIcon&lt;/li&gt;&lt;li&gt;SecondaryIcon&lt;/li&gt;&lt;li&gt;Text&lt;/li&gt;&lt;li&gt;OnClick&lt;/li&gt;&lt;/ul&gt;The cell value can be accessed in function passed to &lt;em&gt;OnClick&lt;/em&gt; via &lt;em&gt;data-cell-value&lt;/em&gt; attribute of sender (for example like this: &lt;em&gt;$(this).attr('data-cell-value');&lt;/em&gt;).&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;In couple next days I'm going to update &lt;a href="http://tpeczek.codeplex.com/releases/view/62741"&gt;the sample project&lt;/a&gt; in order to show some of this functionality.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=69SKJVaUMIE:JyHOMt7GRGc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=69SKJVaUMIE:JyHOMt7GRGc:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/69SKJVaUMIE" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2013/02/jqgrid-strongly-typed-helper-jquery-ui.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-rF_BKvDLaeA/TYJgI6fb7aI/AAAAAAAAANg/xXYpsvT2PP4/s72-c/lib-web-mvc-nuget.png" height="72" width="72" /><thr:total>6</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-7344922319761639257</guid><pubDate>Fri, 11 Jan 2013 21:08:00 +0000</pubDate><atom:updated>2013-01-11T22:08:27.053+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">lib.web.mvc</category><category domain="http://www.blogger.com/atom/ns#">jqgrid</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><title>Using alpha Lib.Web.Mvc NuGet packages from MyGet</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;I`ve setup a package source at &lt;a href="http://www.myget.org/"&gt;MyGet&lt;/a&gt; for alpha releases of &lt;a href="http://tpeczek.codeplex.com/"&gt;Lib.Web.Mvc&lt;/a&gt;. This post describes how to configure Visual Studio in order to use it.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The alpha packages come with no guarantees and they do not substitute for the official NuGet packages.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;&lt;strong&gt;Adding Package Source&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;In order to use the alpha packages you first need to add a package source to Visual Studio pointing to the MyGet feed at &lt;a href="http://www.myget.org/F/libwebmvc/"&gt;http://www.myget.org/F/libwebmvc/&lt;/a&gt;. Under the Visual Studio &lt;em&gt;Tools&lt;/em&gt; menu select &lt;em&gt;Options&lt;/em&gt; and follow below steps:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" border="0" src="http://2.bp.blogspot.com/-cRE4BCdM38o/UPB2hQMK50I/AAAAAAAAASc/yt45Y54RCVg/s1600/Package%2BManager%2BConfiguration.png" /&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Expand &lt;em&gt;Package Manager&lt;/em&gt; node&lt;/li&gt;&lt;li&gt;Choose &lt;em&gt;Package Sources&lt;/em&gt; node&lt;/li&gt;&lt;li&gt;Click the &lt;em&gt;Add&lt;/em&gt; button&lt;/li&gt;&lt;li&gt;Fill in the &lt;em&gt;Name&lt;/em&gt; and the &lt;em&gt;Source&lt;/em&gt; fields.&lt;/li&gt;&lt;li&gt;Click the &lt;em&gt;Update&lt;/em&gt; button&lt;/li&gt;&lt;li&gt;Click the &lt;em&gt;Ok&lt;/em&gt; button to close the options&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;&lt;strong&gt;Using Package Source&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;In order to use the alpha packages in Visual Studio project under the Visual Studio &lt;em&gt;Project&lt;/em&gt; menu select &lt;em&gt;Manage NuGet Packages&lt;/em&gt;:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" border="0" src="http://2.bp.blogspot.com/-GABqFbGM6Es/UPB7Y8q06HI/AAAAAAAAASw/Ls_crbweOHE/s1600/Manage%2BNuGet%2Bpackages.png" /&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Expand &lt;em&gt;Online&lt;/em&gt; node&lt;/li&gt;&lt;li&gt;Choose the node corresponding to previously added source&lt;/li&gt;&lt;li&gt;Choose the &lt;em&gt;Include Prerelease&lt;/em&gt; option from dropdown&lt;/li&gt;&lt;li&gt;Click the &lt;em&gt;Install&lt;/em&gt; button&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This will add the latest alpha version of Lib.Web.Mvc to the project.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=CG2Z-YJa2qk:UxiJeL_rUok:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=CG2Z-YJa2qk:UxiJeL_rUok:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/CG2Z-YJa2qk" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2013/01/using-alpha-libwebmvc-nuget-packages.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-cRE4BCdM38o/UPB2hQMK50I/AAAAAAAAASc/yt45Y54RCVg/s72-c/Package%2BManager%2BConfiguration.png" height="72" width="72" /><thr:total>11</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-2665709202689874177</guid><pubDate>Sun, 20 May 2012 20:15:00 +0000</pubDate><atom:updated>2012-05-20T22:15:05.146+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">jquery</category><category domain="http://www.blogger.com/atom/ns#">jqgrid</category><category domain="http://www.blogger.com/atom/ns#">grid</category><category domain="http://www.blogger.com/atom/ns#">jquery ui</category><title>Switching from jqGrid to jQuery UI Grid - Proof-of-Concept Dataview extension</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;One of projects I'm working on is in very early design stage. Initially we have proposed &lt;em&gt;jqGrid&lt;/em&gt; as a client-side grid widget, but because the project will be using &lt;em&gt;jQuery UI&lt;/em&gt; the requirement was made that &lt;em&gt;jqGrid&lt;/em&gt; can be changed to &lt;em&gt;jQuery UI Grid&lt;/em&gt; when it will be ready. I have made a suggestion that this can be achieved without changes on server-side, thanks to custom &lt;a href="http://wiki.jqueryui.com/w/page/47179141/Dataview"&gt;Dataview&lt;/a&gt; extension which would make the requests in the same why as &lt;em&gt;jqGrid&lt;/em&gt; does. Whenever there is an idea, there should be a proof-of-concept for it.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This implementation is just a proof-of-concept as the jQuery UI Grid plugin is in a pre-release version. Specific technical details may change in future.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;I have described general aspects of &lt;em&gt;Dataview extension&lt;/em&gt; in my &lt;a href="http://tpeczek.blogspot.com/2012/05/another-early-look-at-jquery-ui-grid-in.html"&gt;previous post&lt;/a&gt; so I will focus on the &lt;em&gt;jqGrid&lt;/em&gt; specific aspects of implementation. First the values for &lt;em&gt;nd&lt;/em&gt;, &lt;em&gt;rows&lt;/em&gt; and &lt;em&gt;page&lt;/em&gt; parameters should be set based on the current time and &lt;em&gt;request.paging&lt;/em&gt; properties.&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: js;"&gt;
var data = {
  &amp;quot;nd&amp;quot;: new Date().getTime(),
  &amp;quot;rows&amp;quot;: request.paging.limit,
  &amp;quot;page&amp;quot;: (request.paging.offset / request.paging.limit) + 1
};
&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Sorting is supported in &lt;em&gt;jqGrid&lt;/em&gt; through &lt;em&gt;sidx&lt;/em&gt; and &lt;em&gt;sord&lt;/em&gt; parameters - those need to be extracted from &lt;em&gt;request.sort&lt;/em&gt; option.&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: js;"&gt;
if (request.sort.length === 1) {
  if (request.sort[0].slice(0, 1) === &amp;quot;-&amp;quot;) {
    data[&amp;quot;sidx&amp;quot;] = request.sort[0].slice(1);
    data[&amp;quot;sord&amp;quot;] = &amp;quot;desc&amp;quot;;
  } else {
    data[&amp;quot;sidx&amp;quot;] = request.sort[0];
    data[&amp;quot;sord&amp;quot;] = &amp;quot;asc&amp;quot;;
  }
}
&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;For filtering I've decided to go with implementation which would send filters in the same way as &lt;em&gt;jqGrid&lt;/em&gt; advanced searching does.&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: js;"&gt;
if (request.filter) {
  var filters = [];
  $.each(request.filter, function (property, filter) {
    if (!filter.operator) {
      filter.operator = isNaN(filter.value) ? &amp;quot;like&amp;quot; : &amp;quot;==&amp;quot;;
    }

    var operators = {
      &amp;quot;&amp;lt;&amp;quot;: &amp;quot;lt&amp;quot;,
      &amp;quot;&amp;lt;=&amp;quot;: &amp;quot;le&amp;quot;,
      &amp;quot;&amp;gt;&amp;quot;: &amp;quot;gt&amp;quot;,
      &amp;quot;&amp;gt;=&amp;quot;: &amp;quot;ge&amp;quot;,
      &amp;quot;==&amp;quot;: &amp;quot;eq&amp;quot;,
      &amp;quot;!=&amp;quot;: &amp;quot;ne&amp;quot;,
      &amp;quot;like&amp;quot;: &amp;quot;bw&amp;quot;
    };

    filters[filters.length] = &amp;quot;{\&amp;quot;field\&amp;quot;:\&amp;quot;&amp;quot; + property + &amp;quot;\&amp;quot;,\&amp;quot;op\&amp;quot;:\&amp;quot;&amp;quot; + operators[filter.operator] + &amp;quot;\&amp;quot;,\&amp;quot;data\&amp;quot;:\&amp;quot;&amp;quot; + filter.value + &amp;quot;\&amp;quot;}&amp;quot;;
  });

  data[&amp;quot;_search&amp;quot;] = true;
  data[&amp;quot;filters&amp;quot;] = &amp;quot;{\&amp;quot;groupOp\&amp;quot;:\&amp;quot;AND\&amp;quot;,\&amp;quot;rules\&amp;quot;:[&amp;quot; + filters.join(&amp;quot;,&amp;quot;) + &amp;quot;]}&amp;quot;;
} else {
  data[&amp;quot;_search&amp;quot;] = false;
}
&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now the parameters can be send to server and the response processed. I've added an additional &lt;em&gt;methodType&lt;/em&gt; option for request control.&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: js;"&gt;
$.ajax({
  url: request.resource,
  type: request.methodType,
  dataType: &amp;quot;json&amp;quot;,
  data: data,
  success: function (data) {
    response(data.rows, data.records);
  }
});
&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;I'm going to keep working on this &lt;a href="https://github.com/tpeczek/dataview-jqgrid"&gt;project at GitHub&lt;/a&gt; in order to add support for some more &lt;em&gt;jqGrid&lt;/em&gt; options and keep it up to date with changes in &lt;em&gt;jQuery UI Grid&lt;/em&gt;.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=kqOMAXURhOE:G6TB25SOPO8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=kqOMAXURhOE:G6TB25SOPO8:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/kqOMAXURhOE" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2012/05/switching-from-jqgrid-to-jquery-ui-grid.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-2718263752813233656</guid><pubDate>Thu, 10 May 2012 20:22:00 +0000</pubDate><atom:updated>2012-05-19T22:03:04.177+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">jquery</category><category domain="http://www.blogger.com/atom/ns#">grid</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><category domain="http://www.blogger.com/atom/ns#">jquery ui</category><title>Another early look at jQuery UI Grid in ASP.NET MVC – Data Types, Dataview, Pager, Sorting and Filtering</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;More than a year ago I took my &lt;a href="http://tpeczek.blogspot.com/2011/02/early-look-at-jquery-ui-grid-in-aspnet.html"&gt;first early look at jQuery UI Grid&lt;/a&gt;. Since that time a lot has changed in the plugin (and a lot will as &lt;a href="http://wiki.jqueryui.com/w/page/12138038/Roadmap"&gt;the roadmap&lt;/a&gt; is placing &lt;em&gt;Grid&lt;/em&gt; in 2.1 version of &lt;em&gt;jQuery UI&lt;/em&gt;), so I've decided to take another early look at it.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This blog post talks about jQuery UI Grid plugin in Stage 3 of development, which is a pre-release version. Specific technical details may change before the final release of this product.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This is a minimal set of CSS and JavaScript files required by the plugin:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery-1.7.2.min.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery.tmpl.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/ui/jquery.ui.core.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/ui/jquery.ui.widget.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/ui/jquery.ui.observable.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/ui/jquery.ui.dataview.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/ui/jquery.ui.grid.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;You can find &lt;em&gt;Grid&lt;/em&gt; specific files in its &lt;a href="https://github.com/jquery/jquery-ui/tree/grid"&gt;branch&lt;/a&gt; at GitHub (there is also a &lt;a href="https://github.com/jquery/jquery-ui/tree/grid-jsrender"&gt;branch&lt;/a&gt; which is using &lt;em&gt;JsRender&lt;/em&gt; instead of &lt;em&gt;jQuery Templates&lt;/em&gt;).&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The &lt;em&gt;Grid&lt;/em&gt; is design to be used on &lt;em&gt;table&lt;/em&gt; element. By default it will use the &lt;em&gt;th&lt;/em&gt; elements text and &lt;em&gt;data-*&lt;/em&gt; attributes for setting its &lt;em&gt;columns&lt;/em&gt; and &lt;em&gt;rowTemplate&lt;/em&gt; options. Thanks to that following markup is all what we need:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;table id=&amp;quot;products&amp;quot;&amp;gt;
  &amp;lt;thead&amp;gt;
    &amp;lt;tr&amp;gt;
      &amp;lt;th data-property=&amp;quot;Id&amp;quot; data-type=&amp;quot;number&amp;quot;&amp;gt;Id&amp;lt;/th&amp;gt;
      &amp;lt;th data-property=&amp;quot;Name&amp;quot; data-type=&amp;quot;string&amp;quot;&amp;gt;Name&amp;lt;/th&amp;gt;
      &amp;lt;th data-property=&amp;quot;Supplier.Name&amp;quot; data-type=&amp;quot;string&amp;quot;&amp;gt;Supplier&amp;lt;/th&amp;gt;
      &amp;lt;th data-property=&amp;quot;Category.Name&amp;quot; data-type=&amp;quot;string&amp;quot;&amp;gt;Category&amp;lt;/th&amp;gt;
      &amp;lt;th data-property=&amp;quot;QuantityPerUnit&amp;quot; data-type=&amp;quot;string&amp;quot;&amp;gt;Quantity Per Unit&amp;lt;/th&amp;gt;
      &amp;lt;th data-property=&amp;quot;UnitPrice&amp;quot; data-type=&amp;quot;number&amp;quot;&amp;gt;Unit Price&amp;lt;/th&amp;gt;
      &amp;lt;th data-property=&amp;quot;UnitsInStock&amp;quot; data-type=&amp;quot;number&amp;quot;&amp;gt;Units In Stock&amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
  &amp;lt;/thead&amp;gt;
  &amp;lt;tbody&amp;gt;
  &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;If the default behaviour doesn't give the desired effect, developer can provide values for &lt;em&gt;columns&lt;/em&gt; and &lt;em&gt;rowTemplate&lt;/em&gt; himself. The &lt;em&gt;rowTemplate&lt;/em&gt; option should be set to &lt;em&gt;jQuery Templates&lt;/em&gt; template and the &lt;em&gt;columns&lt;/em&gt; option should be set to an array of objects.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Currently planned low-level abstraction for retrieving data in &lt;em&gt;jQuery UI&lt;/em&gt; project is &lt;a href="http://wiki.jqueryui.com/w/page/47179141/Dataview"&gt;Dataview&lt;/a&gt;, there are also three reusable extensions than we can play with: &lt;em&gt;localDataview&lt;/em&gt;, &lt;em&gt;odataDataview&lt;/em&gt;, &lt;em&gt;preloaderDataview&lt;/em&gt;. In my sample projects I'm already using &lt;em&gt;LINQ Dynamic Query Library&lt;/em&gt; so I thought it would be nice to have &lt;em&gt;Dataview&lt;/em&gt; which would generate sorting and filtering expressions in a way I need them. General structure of &lt;em&gt;Dataview&lt;/em&gt; extension looks like this:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: js;"&gt;
(function($, undefined) {
  $.widget('ui.linqDataview', $.ui.dataview, {
    widgetEventPrefix: 'dataview',
      options: {
        //Here you can provide any additional options you want
        ...
        //This function will be called by Dataview to retrieve data
        source: function (request, response) {
          //'request' contains informations for data scope:
          //- request.paging.offset
          //- request.paging.limit
          //- request.sort.length
          //- request.filter (with request.filter[property].operator and request.filter[property].value)
          ...
          //when you fetch the data the 'response' function should be called
          //with actual data as first parameter and total rows count as second
        }
      }
  });
}(jQuery));
&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;You can find the implementation for my usage of &lt;em&gt;LINQ Dynamic Query Library&lt;/em&gt; purposes &lt;a href="http://tpeczek.codeplex.com/SourceControl/changeset/view/77461#1575657"&gt;here&lt;/a&gt;. Thanks to this the action method for serving data can be as simple as this:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;
public ActionResult Products(int skip, int take, string orderby, string filter)
{
  var products = null;  
  if (!String.IsNullOrWhiteSpace(filter))
    products = _northwindContext.Products.Where(filter);
  else
    products = _northwindContext.Products;
  
  return Json(new
  {
    rows = products.Include(p =&amp;gt; p.Category).Include(p =&amp;gt; p.Supplier).OrderBy(orderby).Skip(skip).Take(take),
    count = products.Count()
  }, JsonRequestBehavior.AllowGet);
}
&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The &lt;em&gt;LINQ Dynamic Query Library&lt;/em&gt; will do the rest.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;On the client side I just need to reference the script file with the &lt;em&gt;Dataview&lt;/em&gt; extension and initialize the widgets:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: js;"&gt;
...
&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/grid-spf/dataview-linq.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
...
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
  $(document).ready(function () {
    //Create Dataview based on the extension
    var products = $.ui.linqDataview({
      //Default sorting
      sort: ['Id'],
      //Action URL
      resource: '@Url.Action(&amp;quot;Products&amp;quot;)'
    });

    //Initialize the grid
    $('#products').grid({
      source: products
    });

    //Load from Dataview
    products.refresh();
  });
&amp;lt;/script&amp;gt;
&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;To make full use of &lt;em&gt;Dataview&lt;/em&gt; capabilities we should add pager, sorting and filtering. We can find basic implementation for those features in &lt;a href="https://github.com/jquery/jquery-ui/tree/grid/grid-spf"&gt;grid-spf&lt;/a&gt; folder at GitHub. Before using those a placeholder for the pager needs to be added to the &lt;em&gt;table&lt;/em&gt; element:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: xml;"&gt;
&amp;lt;table id=&amp;quot;products&amp;quot;&amp;gt;
  ...
  &amp;lt;tfoot&amp;gt;
    &amp;lt;tr&amp;gt;
      &amp;lt;td colspan=&amp;quot;7&amp;quot;&amp;gt;
        &amp;lt;span id=&amp;quot;pager&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;
      &amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
  &amp;lt;/tfoot&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now it's time to add remaining references and extend the initialization code:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: js;"&gt;
...
&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/ui/jquery.ui.button.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/grid-spf/pager.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/grid-spf/grid-sort.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/grid-spf/grid-filter.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
...
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
  $(document).ready(function () {
    ...

    //Initialize the grid
    $('#products').grid({
      source: products
    })
    //Enable sorting
    .gridSort()
    //Enable filtering
    .gridFilter();

    //Initialize pager
    $(&amp;quot;#pager&amp;quot;).pager({
      source: products
    });

    //Load from Dataview
    products.refresh();
  });
&amp;lt;/script&amp;gt;
&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Everything is up and running now. The complete project is available in my &lt;a href="https://tpeczek.svn.codeplex.com/svn/trunk/MVC/jQuery%20UI%20Grid%20Examples/"&gt;svn repository&lt;/a&gt; at CodePlex.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=4jayq1jOf7I:46TDUU-hicw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=4jayq1jOf7I:46TDUU-hicw:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/4jayq1jOf7I" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2012/05/another-early-look-at-jquery-ui-grid-in.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><thr:total>8</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-791679215733004200</guid><pubDate>Sun, 01 Apr 2012 18:50:00 +0000</pubDate><atom:updated>2012-04-01T20:50:25.389+02:00</atom:updated><title>Infinite Scroll in ASP.NET MVC</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Recently I've decided to play a little bit with &lt;em&gt;Infinite Scroll&lt;/em&gt; interaction design pattern as I was planning on using it in one of my upcoming projects. My key requirement was to implement the pattern as an enhancement which would not break the existing navigation/pagination mechanism for users with JavaScript disabled.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;For starters I needed a view which would server content in paged chunks, so I took advantage of the &lt;a href="http://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx"&gt;Razor helpers&lt;/a&gt; and created this piece of code for rendering a pager:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;@helper Pager(int currentPageIndex, int pageRecordsCount, int totalRecordsCount) {&lt;br /&gt;    &lt;br /&gt;  int totalPagesCount = (int)Math.Ceiling((double)totalRecordsCount / (double)pageRecordsCount);&lt;br /&gt;  int numberOfPagesToDisplay = 10;&lt;br /&gt;&lt;br /&gt;  int firstDisplayedPageIndex = 1;&lt;br /&gt;  int lastDisplayedPageIndex = totalPagesCount;&lt;br /&gt;  if (totalPagesCount &amp;gt; numberOfPagesToDisplay)&lt;br /&gt;  {&lt;br /&gt;    int middleDisplayedPageIndex = (int)Math.Ceiling((double)numberOfPagesToDisplay / 2d) - 1;&lt;br /&gt;    firstDisplayedPageIndex = (currentPageIndex - middleDisplayedPageIndex);&lt;br /&gt;    lastDisplayedPageIndex = (currentPageIndex + middleDisplayedPageIndex);&lt;br /&gt;    if (firstDisplayedPageIndex &amp;lt; 4)&lt;br /&gt;    {&lt;br /&gt;      lastDisplayedPageIndex = numberOfPagesToDisplay;&lt;br /&gt;      firstDisplayedPageIndex = 1;&lt;br /&gt;    }&lt;br /&gt;    else if (lastDisplayedPageIndex &amp;gt; (totalPagesCount - 4))&lt;br /&gt;    {&lt;br /&gt;      lastDisplayedPageIndex = totalPagesCount;&lt;br /&gt;      firstDisplayedPageIndex = (totalPagesCount - numberOfPagesToDisplay + 1);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;    &lt;br /&gt;  &amp;lt;div id=&amp;quot;pager&amp;quot; class=&amp;quot;ui-helper-clearfix&amp;quot;&amp;gt;&lt;br /&gt;  @if (currentPageIndex &amp;gt; 1) {&lt;br /&gt;    @Html.ActionLink(&amp;quot;&amp;lt;&amp;quot;, &amp;quot;Products&amp;quot;, new { page = currentPageIndex - 1 }, new { @class = &amp;quot;ui-state-default ui-corner-all&amp;quot; })&lt;br /&gt;  } else {&lt;br /&gt;    &amp;lt;span class=&amp;quot;ui-state-default ui-corner-all ui-state-disabled&amp;quot;&amp;gt;&amp;amp;lt;&amp;lt;/span&amp;gt;&lt;br /&gt;  }&lt;br /&gt;  @if (firstDisplayedPageIndex &amp;gt; 1) {&lt;br /&gt;    @Html.ActionLink(&amp;quot;1&amp;quot;, &amp;quot;Products&amp;quot;, new { page = 1 }, new { @class = &amp;quot;ui-state-default ui-corner-all&amp;quot; })&lt;br /&gt;    if (firstDisplayedPageIndex &amp;gt; 3) {&lt;br /&gt;      @Html.ActionLink(&amp;quot;2&amp;quot;, &amp;quot;Products&amp;quot;, new { page = 2 }, new { @class = &amp;quot;ui-state-default ui-corner-all&amp;quot; })&lt;br /&gt;    }&lt;br /&gt;    if (firstDisplayedPageIndex &amp;gt; 2) {&lt;br /&gt;      &amp;lt;span&amp;gt;...&amp;lt;/span&amp;gt;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  @for (int displayedPageIndex = firstDisplayedPageIndex; displayedPageIndex &amp;lt;= lastDisplayedPageIndex; displayedPageIndex++) {&lt;br /&gt;    if (displayedPageIndex == currentPageIndex || (currentPageIndex &amp;lt;= 0 &amp;amp;&amp;amp; displayedPageIndex == 0)) {&lt;br /&gt;      @Html.Raw(String.Format(&amp;quot;&amp;lt;span class=\&amp;quot;ui-state-hover ui-corner-all\&amp;quot;&amp;gt;{0}&amp;lt;/span&amp;gt;&amp;quot;, displayedPageIndex))&lt;br /&gt;    } else {&lt;br /&gt;      @Html.ActionLink(displayedPageIndex.ToString(), &amp;quot;Products&amp;quot;, new { page = displayedPageIndex }, new { @class = &amp;quot;ui-state-default ui-corner-all&amp;quot; })&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  @if (lastDisplayedPageIndex &amp;lt; totalPagesCount) {&lt;br /&gt;    if (lastDisplayedPageIndex &amp;lt; totalPagesCount - 1) {&lt;br /&gt;      &amp;lt;span&amp;gt;...&amp;lt;/span&amp;gt;&lt;br /&gt;    }&lt;br /&gt;    if (totalPagesCount - 2 &amp;gt; lastDisplayedPageIndex) {&lt;br /&gt;      @Html.ActionLink((totalPagesCount - 1).ToString(), &amp;quot;Products&amp;quot;, new { page = totalPagesCount - 1 }, new { @class = &amp;quot;ui-state-default ui-corner-all&amp;quot; })&lt;br /&gt;    }&lt;br /&gt;    @Html.ActionLink(totalPagesCount.ToString(), &amp;quot;Products&amp;quot;, new { page = totalPagesCount }, new { @class = &amp;quot;ui-state-default ui-corner-all&amp;quot; })&lt;br /&gt;  }&lt;br /&gt;  @if (currentPageIndex &amp;lt; totalPagesCount) {&lt;br /&gt;   @Html.ActionLink(&amp;quot;&amp;gt;&amp;quot;, &amp;quot;Products&amp;quot;, new { page = currentPageIndex + 1 }, new { @class = &amp;quot;ui-state-default ui-corner-all&amp;quot; })&lt;br /&gt;  } else {&lt;br /&gt;    &amp;lt;span class=&amp;quot;ui-state-default ui-corner-all ui-state-disabled&amp;quot;&amp;gt;&amp;amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;  }&lt;br /&gt;  &amp;lt;/div&amp;gt;&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;So this helper (with a little bit of CSS) should render nice pager like this:&lt;/span&gt;&lt;div style="clear: both" class="separator"&gt;&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" alt="jqGrid with caption layer enabled" src="http://4.bp.blogspot.com/-AAgPF_7Dc2E/T3iQeU-X_OI/AAAAAAAAAP4/cekLBs6IlIw/s1600/pager.png" /&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;For the model and repositories I have used good old &lt;em&gt;Northwind&lt;/em&gt; database and Entity Framework Code First. I will skip implementation details here (all projects required by the solution are available through my repository at &lt;a href="http://tpeczek.codeplex.com/"&gt;Codeplex&lt;/a&gt;) and go straight to view model:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;public class ProductsViewModel&lt;br /&gt;{&lt;br /&gt;  #region Properties&lt;br /&gt;  public int CurrentPageIndex { get; set; }&lt;br /&gt;&lt;br /&gt;  public int PageRecordsCount { get; set; }&lt;br /&gt;&lt;br /&gt;  public int TotalRecordsCount { get; set; }&lt;br /&gt;&lt;br /&gt;  public IEnumerable&amp;lt;Product&amp;gt; Products { get; set; }&lt;br /&gt;  #endregion&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The last two things remaining are controller:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;public class HomeController : Controller&lt;br /&gt;{&lt;br /&gt;  #region Fields&lt;br /&gt;  IProductsRepository _productsRepository;&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region Constructors&lt;br /&gt;  public HomeController()&lt;br /&gt;    : this(new ProductsRepository())&lt;br /&gt;  { }&lt;br /&gt;&lt;br /&gt;  public HomeController(IProductsRepository productsRepository)&lt;br /&gt;  {&lt;br /&gt;    _productsRepository = productsRepository;&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region Actions&lt;br /&gt;  public ViewResult Products(int? page)&lt;br /&gt;  {&lt;br /&gt;    ProductsViewModel viewModel = new ProductsViewModel()&lt;br /&gt;    {&lt;br /&gt;      CurrentPageIndex = page.HasValue ? page.Value : 1,&lt;br /&gt;      PageRecordsCount = 10,&lt;br /&gt;      TotalRecordsCount = _productsRepository.GetCount(String.Empty)&lt;br /&gt;    };&lt;br /&gt;    viewModel.Products = _productsRepository.FindRange(String.Empty, &amp;quot;Name&amp;quot;, (viewModel.CurrentPageIndex - 1) * viewModel.PageRecordsCount, viewModel.PageRecordsCount);&lt;br /&gt;&lt;br /&gt;    return View(viewModel);&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;and the actual view:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: xml;"&gt;@model jQuery.InfiniteScroll.Models.ProductsViewModel&lt;br /&gt;@{ ViewBag.Title = &amp;quot;Infinite Scroll in ASP.NET MVC&amp;quot;; }&lt;br /&gt;@helper Pager(int currentPageIndex, int pageRecordsCount, int totalRecordsCount) {&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;&amp;lt;div id=&amp;quot;list&amp;quot;&amp;gt;&lt;br /&gt;    @foreach (Northwind.Model.Product product in Model.Products)&lt;br /&gt;    {&lt;br /&gt;        &amp;lt;div class=&amp;quot;ui-corner-all&amp;quot;&amp;gt;&lt;br /&gt;            &amp;lt;strong&amp;gt;Name:&amp;lt;/strong&amp;gt; @product.Name&amp;lt;br /&amp;gt;&lt;br /&gt;            &amp;lt;strong&amp;gt;Category:&amp;lt;/strong&amp;gt; @product.Category.Name&amp;lt;br /&amp;gt;&lt;br /&gt;            &amp;lt;strong&amp;gt;Supplier:&amp;lt;/strong&amp;gt; @product.Supplier.Name&amp;lt;br /&amp;gt;&lt;br /&gt;            &amp;lt;strong&amp;gt;Unit price:&amp;lt;/strong&amp;gt; @product.UnitPrice&amp;lt;br /&amp;gt;&lt;br /&gt;            &amp;lt;strong&amp;gt;Quantity per unit:&amp;lt;/strong&amp;gt; @product.QuantityPerUnit&amp;lt;br /&amp;gt;&lt;br /&gt;            &amp;lt;strong&amp;gt;Units in stock:&amp;lt;/strong&amp;gt; @product.UnitsInStock&amp;lt;br /&amp;gt;&lt;br /&gt;        &amp;lt;/div&amp;gt;&lt;br /&gt;    }&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;@Pager(Model.CurrentPageIndex, Model.PageRecordsCount, Model.TotalRecordsCount)&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The paged list is working. In order to enhance it with infinite scrolling I've decided to use &lt;a href="https://github.com/paulirish/infinite-scroll"&gt;Infinite Scroll jQuery Plugin&lt;/a&gt;. All what is needed to make this plugin work is reference to plugin file in the project and few lines of JavaScript in the view:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: js;"&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;  $(document).ready(function () {&lt;br /&gt;    //Method is called on element containing the list&lt;br /&gt;    $('#list').infinitescroll({&lt;br /&gt;      //Selector for the pager&lt;br /&gt;      navSelector: '#pager',&lt;br /&gt;      //Selector for the anchor to the next page&lt;br /&gt;      nextSelector: '#pager span.ui-state-hover + a',&lt;br /&gt;      //Selector for the list items&lt;br /&gt;      itemSelector: '#list div.ui-corner-all',&lt;br /&gt;      loading: {&lt;br /&gt;        img: '@Url.Content(&amp;quot;~/Content/images/ajax-loader.gif&amp;quot;)',&lt;br /&gt;        msgText: '',&lt;br /&gt;        finishedMsg: ''&lt;br /&gt;      }&lt;br /&gt;    });&lt;br /&gt;  });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now the plugin will hide the pager and make the requests for next pages when user scrolls to the bottom. If JavaScript is not enabled the old pager is still there to do the job (so this solution is completely SEO friendly). The only issue here is that users who has JavaScript enabled still need to request the entire page in the background instead of just the needed part. In some cases this can have quite huge impact on response size. So lets try to tweak this solution a little bit on the server side. The first step will be extracting the list into a partial view:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: xml;"&gt;@model jQuery.InfiniteScroll.Models.ProductsViewModel&lt;br /&gt;@helper Pager(int currentPageIndex, int pageRecordsCount, int totalRecordsCount) {&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;&amp;lt;div id=&amp;quot;list&amp;quot;&amp;gt;&lt;br /&gt;    @foreach (Northwind.Model.Product product in Model.Products)&lt;br /&gt;    {&lt;br /&gt;        &amp;lt;div class=&amp;quot;ui-corner-all&amp;quot;&amp;gt;&lt;br /&gt;            &amp;lt;strong&amp;gt;Name:&amp;lt;/strong&amp;gt; @product.Name&amp;lt;br /&amp;gt;&lt;br /&gt;            &amp;lt;strong&amp;gt;Category:&amp;lt;/strong&amp;gt; @product.Category.Name&amp;lt;br /&amp;gt;&lt;br /&gt;            &amp;lt;strong&amp;gt;Supplier:&amp;lt;/strong&amp;gt; @product.Supplier.Name&amp;lt;br /&amp;gt;&lt;br /&gt;            &amp;lt;strong&amp;gt;Unit price:&amp;lt;/strong&amp;gt; @product.UnitPrice&amp;lt;br /&amp;gt;&lt;br /&gt;            &amp;lt;strong&amp;gt;Quantity per unit:&amp;lt;/strong&amp;gt; @product.QuantityPerUnit&amp;lt;br /&amp;gt;&lt;br /&gt;            &amp;lt;strong&amp;gt;Units in stock:&amp;lt;/strong&amp;gt; @product.UnitsInStock&amp;lt;br /&amp;gt;&lt;br /&gt;        &amp;lt;/div&amp;gt;&lt;br /&gt;    }&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;@Pager(Model.CurrentPageIndex, Model.PageRecordsCount, Model.TotalRecordsCount)&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now the view needs to be modified accordingly:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: xml;"&gt;@model jQuery.InfiniteScroll.Models.ProductsViewModel&lt;br /&gt;@{ ViewBag.Title = &amp;quot;Infinite Scroll in ASP.NET MVC&amp;quot;; }&lt;br /&gt;@Html.Partial(&amp;quot;ProductsList&amp;quot; , Model)&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;  $(document).ready(function () {&lt;br /&gt;    $('#list').infinitescroll({&lt;br /&gt;      navSelector: '#pager',&lt;br /&gt;      nextSelector: '#pager span.ui-state-hover + a',&lt;br /&gt;      itemSelector: '#list div.ui-corner-all',&lt;br /&gt;      loading: {&lt;br /&gt;        img: '@Url.Content(&amp;quot;~/Content/images/ajax-loader.gif&amp;quot;)',&lt;br /&gt;        msgText: '',&lt;br /&gt;        finishedMsg: ''&lt;br /&gt;      }&lt;br /&gt;    });&lt;br /&gt;  });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;In the controller we could use &lt;em&gt;Request.IsAjaxRequest()&lt;/em&gt; method to distinguish between standard and AJAX request but for testing and clarity I prefer having two separate methods. This is why I have created following attributes:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]&lt;br /&gt;public sealed class AcceptAjaxRequestAttribute : ActionMethodSelectorAttribute&lt;br /&gt;{&lt;br /&gt;  #region Properties&lt;br /&gt;  public bool Accept { get; private set; }&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region Constructor&lt;br /&gt;  public AcceptAjaxRequestAttribute(bool accept)&lt;br /&gt;  {&lt;br /&gt;    Accept = accept;&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region ActionMethodSelectorAttribute Members&lt;br /&gt;  public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)&lt;br /&gt;  {&lt;br /&gt;    if (controllerContext == null)&lt;br /&gt;      throw new ArgumentNullException(&amp;quot;controllerContext&amp;quot;);&lt;br /&gt;&lt;br /&gt;    bool isAjaxRequest = (controllerContext.HttpContext.Request[&amp;quot;X-Requested-With&amp;quot;] == &amp;quot;XMLHttpRequest&amp;quot;) || ((controllerContext.HttpContext.Request.Headers != null) &amp;amp;&amp;amp; (controllerContext.HttpContext.Request.Headers[&amp;quot;X-Requested-With&amp;quot;] == &amp;quot;XMLHttpRequest&amp;quot;));&lt;br /&gt;&lt;br /&gt;    return Accept == isAjaxRequest;&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]&lt;br /&gt;public sealed class AjaxRequestAttribute : ActionMethodSelectorAttribute&lt;br /&gt;{&lt;br /&gt;  #region Fields&lt;br /&gt;  private static readonly AcceptAjaxRequestAttribute _innerAttribute = new AcceptAjaxRequestAttribute(true);&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region ActionMethodSelectorAttribute Members&lt;br /&gt;  public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)&lt;br /&gt;  {&lt;br /&gt;    return _innerAttribute.IsValidForRequest(controllerContext, methodInfo);&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]&lt;br /&gt;public sealed class NoAjaxRequestAttribute : ActionMethodSelectorAttribute&lt;br /&gt;{&lt;br /&gt;  #region Fields&lt;br /&gt;  private static readonly AcceptAjaxRequestAttribute _innerAttribute = new AcceptAjaxRequestAttribute(false);&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region ActionMethodSelectorAttribute Members&lt;br /&gt;  public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)&lt;br /&gt;  {&lt;br /&gt;    return _innerAttribute.IsValidForRequest(controllerContext, methodInfo);&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;With help of those attributes and &lt;em&gt;ActionNameAttribute&lt;/em&gt; the controller can be modified like this:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;#region Actions&lt;br /&gt;[NoAjaxRequest]&lt;br /&gt;public ViewResult Products(int? page)&lt;br /&gt;{&lt;br /&gt;  return View(GetProductsViewModel(page));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[AjaxRequest]&lt;br /&gt;[ActionName(&amp;quot;Products&amp;quot;)]&lt;br /&gt;public PartialViewResult ProductsList(int? page)&lt;br /&gt;{&lt;br /&gt;  return PartialView(&amp;quot;ProductsList&amp;quot;, GetProductsViewModel(page));&lt;br /&gt;}&lt;br /&gt;#endregion&lt;br /&gt;&lt;br /&gt;#region Methods&lt;br /&gt;private ProductsViewModel GetProductsViewModel(int? page)&lt;br /&gt;{&lt;br /&gt;  ProductsViewModel viewModel = new ProductsViewModel()&lt;br /&gt;  {&lt;br /&gt;    CurrentPageIndex = page.HasValue ? page.Value : 1,&lt;br /&gt;    PageRecordsCount = 10,&lt;br /&gt;    TotalRecordsCount = _productsRepository.GetCount(String.Empty)&lt;br /&gt;  };&lt;br /&gt;  viewModel.Products = _productsRepository.FindRange(String.Empty, &amp;quot;Name&amp;quot;, (viewModel.CurrentPageIndex - 1) * viewModel.PageRecordsCount, viewModel.PageRecordsCount);&lt;br /&gt;&lt;br /&gt;  return viewModel;&lt;br /&gt;}&lt;br /&gt;#endregion&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Thanks to this the clients with JavaScript support will get only the required HTML while clients with JavaScript disabled will get the entire page for each request.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=xehnyxnsWR8:5hw3cWuLw-c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=xehnyxnsWR8:5hw3cWuLw-c:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/xehnyxnsWR8" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2012/04/infinite-scroll-in-aspnet-mvc.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-AAgPF_7Dc2E/T3iQeU-X_OI/AAAAAAAAAP4/cekLBs6IlIw/s72-c/pager.png" height="72" width="72" /><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-404649263838499778</guid><pubDate>Sun, 09 Oct 2011 17:38:00 +0000</pubDate><atom:updated>2012-01-27T20:09:33.004+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">range requests</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><title>Range Requests in ASP.NET MVC – RangeFileResult</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;In one of small projects I'm involved in there was a need for supporting &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html"&gt;Range Requests&lt;/a&gt;. That wouldn't be an issue if the files were static resources (IIS, as any decent server, has built in support for &lt;em&gt;Range Requests&lt;/em&gt;) but in this case the files were returned from &lt;em&gt;Action&lt;/em&gt;. To solve this problem I've decided to create an &lt;em&gt;ActionResult&lt;/em&gt; which takes care of creating &lt;em&gt;Partial Response&lt;/em&gt; internally.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;To create &lt;em&gt;Partial Response&lt;/em&gt; the &lt;em&gt;ActionResult&lt;/em&gt; will require some basic information about the file. It also has to be able to generate &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.11"&gt;entity tag&lt;/a&gt;:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;public abstract class RangeFileResult : ActionResult&lt;br /&gt;{&lt;br /&gt;  ...&lt;br /&gt;&lt;br /&gt;  #region Properties&lt;br /&gt;  public string ContentType { get; private set; }&lt;br /&gt;&lt;br /&gt;  public string FileName { get; private set; }&lt;br /&gt;&lt;br /&gt;  public DateTime FileModificationDate { get; private set; }&lt;br /&gt;&lt;br /&gt;  private DateTime HttpModificationDate { get; set; }&lt;br /&gt;&lt;br /&gt;  public long FileLength { get; private set; }&lt;br /&gt;&lt;br /&gt;  private string EntityTag { get; set; }&lt;br /&gt;&lt;br /&gt;  private long[] RangesStartIndexes { get; set; }&lt;br /&gt;&lt;br /&gt;  private long[] RangesEndIndexes { get; set; }&lt;br /&gt;&lt;br /&gt;  private bool RangeRequest { get; set; }&lt;br /&gt;&lt;br /&gt;  private bool MultipartRequest { get; set; }&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region Constructor&lt;br /&gt;  protected RangeFileResult(string contentType, string fileName, DateTime modificationDate, long fileLength)&lt;br /&gt;  {&lt;br /&gt;    if (String.IsNullOrEmpty(contentType))&lt;br /&gt;      throw new ArgumentNullException(&amp;quot;contentType&amp;quot;);&lt;br /&gt;&lt;br /&gt;    ContentType = contentType;&lt;br /&gt;    FileName = fileName;&lt;br /&gt;    FileLength = fileLength;&lt;br /&gt;    FileModificationDate = modificationDate;&lt;br /&gt;    //Modification date for header values comparisons purposes&lt;br /&gt;    HttpModificationDate = modificationDate.ToUniversalTime();&lt;br /&gt;    HttpModificationDate = new DateTime(HttpModificationDate.Year, HttpModificationDate.Month, HttpModificationDate.Day, HttpModificationDate.Hour, HttpModificationDate.Minute, HttpModificationDate.Second, DateTimeKind.Utc);&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region Methods&lt;br /&gt;  protected virtual string GenerateEntityTag(ControllerContext context)&lt;br /&gt;  {&lt;br /&gt;    //Generate entity tag based on file name and modification date&lt;br /&gt;    byte[] entityTagBytes = Encoding.ASCII.GetBytes(String.Format(&amp;quot;{0}|{1}&amp;quot;, FileName, FileModificationDate));&lt;br /&gt;    return Convert.ToBase64String(new MD5CryptoServiceProvider().ComputeHash(entityTagBytes));&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  ...&lt;br /&gt;  #endregion&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we should get the actual &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1"&gt;byte range(s)&lt;/a&gt; from the request:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;#region Fields&lt;br /&gt;private static char[] _commaSplitArray = new char[] { ',' };&lt;br /&gt;private static char[] _dashSplitArray = new char[] { '-' };&lt;br /&gt;private static string[] _httpDateFormats = new string[] { &amp;quot;r&amp;quot;, &amp;quot;dddd, dd-MMM-yy HH':'mm':'ss 'GMT'&amp;quot;, &amp;quot;ddd MMM d HH':'mm':'ss yyyy&amp;quot; };&lt;br /&gt;#endregion&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;#region Methods&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;//Helper method for getting HTTP headers values&lt;br /&gt;private string GetHeader(HttpRequestBase request, string header, string defaultValue = &amp;quot;&amp;quot;)&lt;br /&gt;{&lt;br /&gt;  return String.IsNullOrEmpty(request.Headers[header]) ? defaultValue : request.Headers[header].Replace(&amp;quot;\&amp;quot;&amp;quot;, String.Empty);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private void GetRanges(HttpRequestBase request)&lt;br /&gt;{&lt;br /&gt;  //Get &amp;quot;Range&amp;quot; header from request&lt;br /&gt;  string rangesHeader = GetHeader(request, &amp;quot;Range&amp;quot;);&lt;br /&gt;  //Get &amp;quot;If-Range&amp;quot; header from request&lt;br /&gt;  string ifRangeHeader = GetHeader(request, &amp;quot;If-Range&amp;quot;, EntityTag);&lt;br /&gt;  DateTime ifRangeHeaderDate;&lt;br /&gt;  bool isIfRangeHeaderDate = DateTime.TryParseExact(ifRangeHeader, _httpDateFormats, null, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out ifRangeHeaderDate);&lt;br /&gt;&lt;br /&gt;  //If there is no &amp;quot;Range&amp;quot; header,&lt;br /&gt;  //or the entity tag from &amp;quot;If-Range&amp;quot; header does not match this entity tag,&lt;br /&gt;  //or the modification date is greater than modification date from &amp;quot;If-Range&amp;quot; header&lt;br /&gt;  if (String.IsNullOrEmpty(rangesHeader) || (!isIfRangeHeaderDate &amp;amp;&amp;amp; ifRangeHeader != EntityTag) || (isIfRangeHeaderDate &amp;amp;&amp;amp; HttpModificationDate &amp;gt; ifRangeHeaderDate))&lt;br /&gt;  {&lt;br /&gt;    //Return entire file&lt;br /&gt;    RangesStartIndexes = new long[] { 0 };&lt;br /&gt;    RangesEndIndexes = new long[] { FileLength - 1 };&lt;br /&gt;    RangeRequest = false;&lt;br /&gt;    MultipartRequest = false;&lt;br /&gt;  }&lt;br /&gt;  //Otherwise&lt;br /&gt;  else&lt;br /&gt;  {&lt;br /&gt;    //Split &amp;quot;Range&amp;quot; header value into ranges&lt;br /&gt;    string[] ranges = rangesHeader.Replace(&amp;quot;bytes=&amp;quot;, String.Empty).Split(_commaSplitArray);&lt;br /&gt;&lt;br /&gt;    RangesStartIndexes = new long[ranges.Length];&lt;br /&gt;    RangesEndIndexes = new long[ranges.Length];&lt;br /&gt;    RangeRequest = true;&lt;br /&gt;    MultipartRequest = (ranges.Length &amp;gt; 1);&lt;br /&gt;&lt;br /&gt;    //Get the star and end index for the range &lt;br /&gt;    for (int i = 0; i &amp;lt; ranges.Length; i++)&lt;br /&gt;    {&lt;br /&gt;      string[] currentRange = ranges[i].Split(_dashSplitArray);&lt;br /&gt;&lt;br /&gt;      if (String.IsNullOrEmpty(currentRange[1]))&lt;br /&gt;        RangesEndIndexes[i] = FileLength - 1;&lt;br /&gt;      else&lt;br /&gt;        RangesEndIndexes[i] = Int64.Parse(currentRange[1]);&lt;br /&gt;&lt;br /&gt;      if (String.IsNullOrEmpty(currentRange[0]))&lt;br /&gt;      {&lt;br /&gt;        RangesStartIndexes[i] = FileLength - 1 - RangesEndIndexes[i];&lt;br /&gt;        RangesEndIndexes[i] = FileLength - 1;&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;        RangesStartIndexes[i] = Int64.Parse(currentRange[0]);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;#endregion&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The ranges have to be validated for consistency:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;private bool ValidateRanges(HttpResponseBase response)&lt;br /&gt;{&lt;br /&gt;  if (FileLength &amp;gt; Int32.MaxValue)&lt;br /&gt;  {&lt;br /&gt;    response.StatusCode = 413;&lt;br /&gt;    return false;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  for (int i = 0; i &amp;lt; RangesStartIndexes.Length; i++)&lt;br /&gt;  {&lt;br /&gt;    if (RangesStartIndexes[i] &amp;gt; FileLength - 1 || RangesEndIndexes[i] &amp;gt; FileLength - 1 || RangesStartIndexes[i] &amp;lt; 0 || RangesEndIndexes[i] &amp;lt; 0 || RangesEndIndexes[i] &amp;lt; RangesStartIndexes[i])&lt;br /&gt;    {&lt;br /&gt;      response.StatusCode = 400;&lt;br /&gt;      return false;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return true;&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;We also should validate modification date against &lt;em&gt;If-Modified-Since&lt;/em&gt;, &lt;em&gt;If-Unmodified-Since&lt;/em&gt; and &lt;em&gt;Unless-Modified-Since&lt;/em&gt; headers:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;private bool ValidateModificationDate(HttpRequestBase request, HttpResponseBase response)&lt;br /&gt;{&lt;br /&gt;  //First validate &amp;quot;If-Modified-Since&amp;quot; header&lt;br /&gt;  string modifiedSinceHeader = GetHeader(request, &amp;quot;If-Modified-Since&amp;quot;);&lt;br /&gt;  if (!String.IsNullOrEmpty(modifiedSinceHeader))&lt;br /&gt;  {&lt;br /&gt;    DateTime modifiedSinceDate;&lt;br /&gt;    DateTime.TryParseExact(modifiedSinceHeader, _httpDateFormats, null, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out modifiedSinceDate);&lt;br /&gt;&lt;br /&gt;    if (HttpModificationDate &amp;lt;= modifiedSinceDate)&lt;br /&gt;    {&lt;br /&gt;      response.StatusCode = 304;&lt;br /&gt;      return false;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  //Then validate &amp;quot;If-Unmodified-Since&amp;quot; or &amp;quot;Unless-Modified-Since&amp;quot;&lt;br /&gt;  string unmodifiedSinceHeader = GetHeader(request, &amp;quot;If-Unmodified-Since&amp;quot;, GetHeader(request, &amp;quot;Unless-Modified-Since&amp;quot;));&lt;br /&gt;  if (!String.IsNullOrEmpty(unmodifiedSinceHeader))&lt;br /&gt;  {&lt;br /&gt;    DateTime unmodifiedSinceDate;&lt;br /&gt;    bool unmodifiedSinceDateParsed = DateTime.TryParseExact(unmodifiedSinceHeader, _httpDateFormats, null, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out unmodifiedSinceDate);&lt;br /&gt;&lt;br /&gt;    if (HttpModificationDate &amp;gt; unmodifiedSinceDate)&lt;br /&gt;    {&lt;br /&gt;      response.StatusCode = 412;&lt;br /&gt;      return false;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return true;&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Last validation is for &lt;em&gt;If-Match&lt;/em&gt; and &lt;em&gt;If-None-Match&lt;/em&gt; headers:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;private bool ValidateEntityTag(HttpRequestBase request, HttpResponseBase response)&lt;br /&gt;{&lt;br /&gt;  //Get &amp;quot;If-Match&amp;quot; header from request&lt;br /&gt;  string matchHeader = GetHeader(request, &amp;quot;If-Match&amp;quot;);&lt;br /&gt;  &lt;br /&gt;  //If header exists and it's value is different from &amp;quot;*&amp;quot;&lt;br /&gt;  if (!String.IsNullOrEmpty(matchHeader) &amp;amp;&amp;amp; matchHeader != &amp;quot;*&amp;quot;)&lt;br /&gt;  {&lt;br /&gt;    //Split header value into list of etity tags&lt;br /&gt;    string[] entitiesTags = matchHeader.Split(_commaSplitArray);&lt;br /&gt;    int entitieTagIndex;&lt;br /&gt;    for (entitieTagIndex = 0; entitieTagIndex &amp;lt; entitiesTags.Length; entitieTagIndex++)&lt;br /&gt;    {&lt;br /&gt;      if (EntityTag == entitiesTags[entitieTagIndex])&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    //If our entity tag wasn't found&lt;br /&gt;    if (entitieTagIndex &amp;gt;= entitiesTags.Length)&lt;br /&gt;    {&lt;br /&gt;      //Set proper response status code&lt;br /&gt;      response.StatusCode = 412;&lt;br /&gt;      return false;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  //Get &amp;quot;If-None-Match&amp;quot; header from request&lt;br /&gt;  string noneMatchHeader = GetHeader(request, &amp;quot;If-None-Match&amp;quot;);&lt;br /&gt;&lt;br /&gt;  //If header exists&lt;br /&gt;  if (!String.IsNullOrEmpty(noneMatchHeader))&lt;br /&gt;  {&lt;br /&gt;    //If header value equals &amp;quot;*&amp;quot;&lt;br /&gt;    if (noneMatchHeader == &amp;quot;*&amp;quot;)&lt;br /&gt;    {&lt;br /&gt;      //Set proper response status code&lt;br /&gt;      response.StatusCode = 412;&lt;br /&gt;      return false;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    //Split header value into list of etity tags&lt;br /&gt;    string[] entitiesTags = noneMatchHeader.Split(_commaSplitArray);&lt;br /&gt;    foreach (string entityTag in entitiesTags)&lt;br /&gt;    {&lt;br /&gt;      if (EntityTag == entityTag)&lt;br /&gt;      {&lt;br /&gt;        //Set proper response status code&lt;br /&gt;        response.AddHeader(&amp;quot;ETag&amp;quot;, String.Format(&amp;quot;\&amp;quot;{0}\&amp;quot;&amp;quot;, entityTag));&lt;br /&gt;        response.StatusCode = 304;&lt;br /&gt;        return false;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return true;&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;We can finally wrap it up and implement &lt;em&gt;ExecuteResult&lt;/em&gt; method:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;protected abstract void WriteEntireEntity(HttpResponseBase response);&lt;br /&gt;&lt;br /&gt;protected abstract void WriteEntityRange(HttpResponseBase response, long rangeStartIndex, long rangeEndIndex);&lt;br /&gt;&lt;br /&gt;public override void ExecuteResult(ControllerContext context)&lt;br /&gt;{&lt;br /&gt;  //Generate entity tag&lt;br /&gt;  EntityTag = GenerateEntityTag(context);&lt;br /&gt;  //Get ranges from request&lt;br /&gt;  GetRanges(context.HttpContext.Request);&lt;br /&gt;&lt;br /&gt;  //If all validations are successful&lt;br /&gt;  if (ValidateRanges(context.HttpContext.Response) &amp;amp;&amp;amp; ValidateModificationDate(context.HttpContext.Request, context.HttpContext.Response) &amp;amp;&amp;amp; ValidateEntityTag(context.HttpContext.Request, context.HttpContext.Response))&lt;br /&gt;  {&lt;br /&gt;    //Set common headers&lt;br /&gt;    context.HttpContext.Response.AddHeader(&amp;quot;Last-Modified&amp;quot;, FileModificationDate.ToString(&amp;quot;r&amp;quot;));&lt;br /&gt;    context.HttpContext.Response.AddHeader(&amp;quot;ETag&amp;quot;, String.Format(&amp;quot;\&amp;quot;{0}\&amp;quot;&amp;quot;, EntityTag));&lt;br /&gt;    context.HttpContext.Response.AddHeader(&amp;quot;Accept-Ranges&amp;quot;, &amp;quot;bytes&amp;quot;);&lt;br /&gt;&lt;br /&gt;    //If this is not range request&lt;br /&gt;    if (!RangeRequest)&lt;br /&gt;    {&lt;br /&gt;      //Set standard headers&lt;br /&gt;      context.HttpContext.Response.AddHeader(&amp;quot;Content-Length&amp;quot;, FileLength.ToString());&lt;br /&gt;      context.HttpContext.Response.ContentType = ContentType;&lt;br /&gt;      //Set status code&lt;br /&gt;      context.HttpContext.Response.StatusCode = 200;&lt;br /&gt;      &lt;br /&gt;      //If this is not HEAD request&lt;br /&gt;      if (!context.HttpContext.Request.HttpMethod.Equals(&amp;quot;HEAD&amp;quot;))&lt;br /&gt;        //Write entire file to response&lt;br /&gt;        WriteEntireEntity(context.HttpContext.Response);&lt;br /&gt;    }&lt;br /&gt;    //If this is range request&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;      string boundary = &amp;quot;---------------------------&amp;quot; + DateTime.Now.Ticks.ToString(&amp;quot;x&amp;quot;);&lt;br /&gt;&lt;br /&gt;      //Compute and set content length&lt;br /&gt;      context.HttpContext.Response.AddHeader(&amp;quot;Content-Length&amp;quot;, GetContentLength(boundary).ToString());&lt;br /&gt;      &lt;br /&gt;      //If this is not multipart request&lt;br /&gt;      if (!MultipartRequest)&lt;br /&gt;      {&lt;br /&gt;        //Set content range and type&lt;br /&gt;        context.HttpContext.Response.AddHeader(&amp;quot;Content-Range&amp;quot;, String.Format(&amp;quot;bytes {0}-{1}/{2}&amp;quot;, RangesStartIndexes[0], RangesEndIndexes[0], FileLength));&lt;br /&gt;        context.HttpContext.Response.ContentType = ContentType;&lt;br /&gt;      }&lt;br /&gt;      //Otherwise&lt;br /&gt;      else&lt;br /&gt;        //Set proper content type&lt;br /&gt;        context.HttpContext.Response.ContentType = String.Format(&amp;quot;multipart/byteranges; boundary={0}&amp;quot;, boundary);&lt;br /&gt;&lt;br /&gt;      //Set status code&lt;br /&gt;      context.HttpContext.Response.StatusCode = 206;&lt;br /&gt;&lt;br /&gt;      //If this not HEAD request&lt;br /&gt;      if (!context.HttpContext.Request.HttpMethod.Equals(&amp;quot;HEAD&amp;quot;))&lt;br /&gt;      {&lt;br /&gt;        //For each requested range&lt;br /&gt;        for (int i = 0; i &amp;lt; RangesStartIndexes.Length; i++)&lt;br /&gt;        {&lt;br /&gt;          //If this is multipart request&lt;br /&gt;          if (MultipartRequest)&lt;br /&gt;          {&lt;br /&gt;            //Write additional multipart info&lt;br /&gt;            context.HttpContext.Response.Write(String.Format(&amp;quot;--{0}\r\n&amp;quot;, boundary));&lt;br /&gt;            context.HttpContext.Response.Write(String.Format(&amp;quot;Content-Type: {0}\r\n&amp;quot;, ContentType));&lt;br /&gt;            context.HttpContext.Response.Write(String.Format(&amp;quot;Content-Range: bytes {0}-{1}/{2}\r\n\r\n&amp;quot;, RangesStartIndexes[i], RangesEndIndexes[i], FileLength));&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          //Write range (with multipart separator if required)&lt;br /&gt;          if (context.HttpContext.Response.IsClientConnected)&lt;br /&gt;          {&lt;br /&gt;            WriteEntityRange(context.HttpContext.Response, RangesStartIndexes[i], RangesEndIndexes[i]);&lt;br /&gt;            if (MultipartRequest)&lt;br /&gt;              context.HttpContext.Response.Write(&amp;quot;\r\n&amp;quot;);&lt;br /&gt;            context.HttpContext.Response.Flush();&lt;br /&gt;          }&lt;br /&gt;          else&lt;br /&gt;            return;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        //If this is multipart request&lt;br /&gt;        if (MultipartRequest)&lt;br /&gt;          context.HttpContext.Response.Write(String.Format(&amp;quot;--{0}--&amp;quot;, boundary));&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//Helper method for computing content length&lt;br /&gt;private int GetContentLength(string boundary)&lt;br /&gt;{&lt;br /&gt;  int contentLength = 0;&lt;br /&gt;&lt;br /&gt;  for (int i = 0; i &amp;lt; RangesStartIndexes.Length; i++)&lt;br /&gt;  {&lt;br /&gt;    contentLength += Convert.ToInt32(RangesEndIndexes[i] - RangesStartIndexes[i]) + 1;&lt;br /&gt;&lt;br /&gt;    if (MultipartRequest)&lt;br /&gt;      contentLength += boundary.Length + ContentType.Length + RangesStartIndexes[i].ToString().Length + RangesEndIndexes[i].ToString().Length + FileLength.ToString().Length + 49;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  if (MultipartRequest)&lt;br /&gt;    contentLength += boundary.Length + 4;&lt;br /&gt;&lt;br /&gt;  return contentLength;&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The base class is now ready, to create any specific implementation we just need to override &lt;em&gt;WriteEntireEntity&lt;/em&gt; and &lt;em&gt;WriteEntityRange&lt;/em&gt; methods:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: small"&gt;&lt;pre class="brush: csharp;"&gt;public class RangeFilePathResult : RangeFileResult&lt;br /&gt;{&lt;br /&gt;  #region Fields&lt;br /&gt;  private const int _bufferSize = 0x1000;&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region Constructor&lt;br /&gt;  public RangeFilePathResult(string contentType, string fileName, DateTime modificationDate, long fileLength)&lt;br /&gt;    : base(contentType, fileName, modificationDate, fileLength)&lt;br /&gt;  {&lt;br /&gt;    if (String.IsNullOrEmpty(fileName))&lt;br /&gt;      throw new ArgumentNullException(&amp;quot;fileName&amp;quot;);&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region Methods&lt;br /&gt;  protected override void WriteEntireEntity(HttpResponseBase response)&lt;br /&gt;  {&lt;br /&gt;    response.TransmitFile(FileName);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  protected override void WriteEntityRange(HttpResponseBase response, long rangeStartIndex, long rangeEndIndex)&lt;br /&gt;  {&lt;br /&gt;    using (FileStream stream = new FileStream(FileName, FileMode.Open, FileAccess.Read))&lt;br /&gt;    {&lt;br /&gt;      stream.Seek(rangeStartIndex, SeekOrigin.Begin);&lt;br /&gt;&lt;br /&gt;      int bytesRemaining = Convert.ToInt32(rangeEndIndex - rangeStartIndex) + 1;&lt;br /&gt;      byte[] buffer = new byte[_bufferSize];&lt;br /&gt;&lt;br /&gt;      while (bytesRemaining &amp;gt; 0)&lt;br /&gt;      {&lt;br /&gt;        int bytesRead = stream.Read(buffer, 0, _bufferSize &amp;lt; bytesRemaining ? _bufferSize : bytesRemaining);&lt;br /&gt;        response.OutputStream.Write(buffer, 0, bytesRead);&lt;br /&gt;        bytesRemaining -= bytesRead;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      stream.Close();&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;I have added the &lt;em&gt;RangeFileResult&lt;/em&gt; class, and following implementations to the latest version of &lt;em&gt;Lib.Web.Mvc&lt;/em&gt;:&lt;ul&gt;&lt;li&gt;RangeFilePathResult&lt;/li&gt;&lt;li&gt;RangeFileStreamResult&lt;/li&gt;&lt;li&gt;RangeFileContentResult&lt;/li&gt;&lt;/ul&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;You can download this release from &lt;a href="http://tpeczek.codeplex.com/releases/view/74713"&gt;here&lt;/a&gt; or go for &lt;em&gt;NuGet&lt;/em&gt; package.&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" border="0" src="http://3.bp.blogspot.com/-rF_BKvDLaeA/TYJgI6fb7aI/AAAAAAAAANg/xXYpsvT2PP4/s1600/lib-web-mvc-nuget.png" /&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;I have also published sample application which shows how to use those classes together with &lt;a href="http://videojs.com/"&gt;VideoJS&lt;/a&gt;, you can download it &lt;a href="http://tpeczek.codeplex.com/releases/view/74711"&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=RfjZlD8H-4o:ebeaJg1HRjM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=RfjZlD8H-4o:ebeaJg1HRjM:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/RfjZlD8H-4o" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2011/10/range-requests-in-aspnet-mvc.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-rF_BKvDLaeA/TYJgI6fb7aI/AAAAAAAAANg/xXYpsvT2PP4/s72-c/lib-web-mvc-nuget.png" height="72" width="72" /><thr:total>9</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-7922472520501522557</guid><pubDate>Sat, 30 Jul 2011 20:32:00 +0000</pubDate><atom:updated>2011-08-01T18:57:18.093+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">jquery</category><category domain="http://www.blogger.com/atom/ns#">helper</category><category domain="http://www.blogger.com/atom/ns#">jqgrid</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><title>jqGrid Strongly Typed Helper - Caption layer, dynamic scrolling and grouping</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Recently, I have released an updated version of my &lt;a href="http://tpeczek.codeplex.com/releases/view/70518"&gt;Lib.Web.Mvc&lt;/a&gt; project, which brings few new functionalities to &lt;a href="http://tpeczek.blogspot.com/2011/03/jqgrid-and-aspnet-mvc-strongly-typed.html"&gt;jqGrid strongly typed helper&lt;/a&gt;. Let me give you a short description of those, starting with support for caption layer:&lt;/span&gt;  &lt;div style="clear: both" class="separator"&gt;&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" alt="jqGrid with caption layer enabled" src="http://2.bp.blogspot.com/-kesR4XB3SF0/Ti8mpurOnUI/AAAAAAAAAPg/0cyyf_dRnNQ/s1600/jqGrid%2BCaption.png" /&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;If you want to enable the caption layer, all you have to do is set &lt;em&gt;JqGridOptions.Caption&lt;/em&gt; property to not empty string (you can also use proper JqGridHelper constructor parameter):&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;@{&lt;br /&gt;  var grid = new Lib.Web.Mvc.JQuery.JqGrid.JqGridHelper&amp;lt;jqGrid.Models.ProductFormattedViewModel&amp;gt;(&amp;quot;products&amp;quot;,&lt;br /&gt;    caption: &amp;quot;Products&amp;quot;,&lt;br /&gt;    ...&lt;br /&gt;  );&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;There two more options for controlling caption layer:&lt;ul&gt;&lt;li&gt;&lt;strong&gt;HiddenEnabled&lt;/strong&gt; - This property defines whether the show/hide grid button is enabled.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Hidden&lt;/strong&gt; - This property defines whether the grid is initially hidden (no data is loaded, only caption layer is shown). This setting takes effect only if the &lt;em&gt;Caption&lt;/em&gt; property is not empty string and &lt;em&gt;HiddenEnabled&lt;/em&gt; is set to true.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Another new functionality supported by the helper is dynamic scrolling. This is supported through &lt;em&gt;JqGridOptions.DynamicScrollingMode&lt;/em&gt; property, which can take one of the following values:&lt;ul&gt;&lt;li&gt;&lt;strong&gt;JqGridDynamicScrollingModes.Disabled&lt;/strong&gt; - Dynamic scrolling is disabled (this is default value).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;JqGridDynamicScrollingModes.HoldAllRows&lt;/strong&gt; - Dynamic scrolling is enabled, the grid will hold all items requested.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;JqGridDynamicScrollingModes.HoldVisibleRows&lt;/strong&gt; - Dynamic scrolling is enabled, the grid will hold only visible rows.&lt;/li&gt;&lt;/ul&gt;When you set this property to value different than &lt;em&gt;Disabled&lt;/em&gt; jqGrid will remove the pager and load data as needed while scrolling. There is a way to optimize this experience by allowing jqGrid to request more than one page of data at once. To achieve this first you must enable &lt;em&gt;npage&lt;/em&gt; parameter through &lt;em&gt;ParametersNames&lt;/em&gt; property:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;@{&lt;br /&gt;  var grid = new Lib.Web.Mvc.JQuery.JqGrid.JqGridHelper&amp;lt;jqGrid.Models.ProductFormattedViewModel&amp;gt;(&amp;quot;products&amp;quot;,&lt;br /&gt;    dynamicScrollingMode: Lib.Web.Mvc.JQuery.JqGrid.JqGridDynamicScrollingModes.HoldAllRows,&lt;br /&gt;    ...&lt;br /&gt;    parametersNames: new Lib.Web.Mvc.JQuery.JqGrid.JqGridParametersNames() { PagesCount = &amp;quot;npage&amp;quot; },&lt;br /&gt;    ...&lt;br /&gt;  );&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now, we just need to modify controller action to support this parameter:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;[AcceptVerbs(HttpVerbs.Post)]&lt;br /&gt;public ActionResult Products(JqGridRequest request, CustomSearchViewModel viewModel)&lt;br /&gt;{&lt;br /&gt;  string filterExpression = String.Empty;&lt;br /&gt;  if (request.Searching)&lt;br /&gt;  {&lt;br /&gt;    //Generate filter expression&lt;br /&gt;    ...&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  int totalRecordsCount = _productsRepository.GetCount(filterExpression);&lt;br /&gt;&lt;br /&gt;  JqGridResponse response = new JqGridResponse()&lt;br /&gt;  {&lt;br /&gt;    TotalPagesCount = (int)Math.Ceiling((float)totalRecordsCount / (float)request.RecordsCount),&lt;br /&gt;    PageIndex = request.PageIndex,&lt;br /&gt;    TotalRecordsCount = totalRecordsCount&lt;br /&gt;  };&lt;br /&gt;  response.Records.AddRange(from product in _productsRepository.FindRange(filterExpression, String.Format(&amp;quot;{0} {1}&amp;quot;, sortingName, request.SortingOrder), request.PageIndex * request.RecordsCount, (request.PagesCount.HasValue ? request.PagesCount.Value : 1) * request.RecordsCount)&lt;br /&gt;                            select new JqGridRecord&amp;lt;ProductFormattedViewModel&amp;gt;(Convert.ToString(product.Id), new ProductFormattedViewModel(product)));&lt;br /&gt;&lt;br /&gt;  return new JqGridJsonResult() { Data= response };&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The user can scroll through the rows and jqGrid will dynamically load all necessary data:&lt;/span&gt;&lt;div style="clear: both" class="separator"&gt;&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" alt="jqGrid dynamic scrolling" src="http://1.bp.blogspot.com/-q9tw0Gk8J1g/Ti8nUtCBTMI/AAAAAAAAAPo/mfsnXeVVO28/s1600/jqGrid%2BDynamic%2BScrolling.png" /&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The last new functionality is grouping. To enable it, you need to set &lt;em&gt;JqGridOptions.GroupingEnabled&lt;/em&gt; to true and assign &lt;em&gt;JqGridGroupingView&lt;/em&gt; to &lt;em&gt;JqGridOptions.GroupingView&lt;/em&gt; option (at this moment jqGrid supports only one grouping level, but the API is ready to support more):&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;@{&lt;br /&gt;  var grid = new Lib.Web.Mvc.JQuery.JqGrid.JqGridHelper&amp;lt;jqGrid.Models.ProductFormattedViewModel&amp;gt;(&amp;quot;products&amp;quot;,&lt;br /&gt;    groupingEnabled: true,&lt;br /&gt;    groupingView: new Lib.Web.Mvc.JQuery.JqGrid.JqGridGroupingView &lt;br /&gt;    {&lt;br /&gt;      Fields = new string[] { &amp;quot;Category&amp;quot; },&lt;br /&gt;      ColumnShow = new bool[] { false },&lt;br /&gt;      Summary = new bool[] { true },&lt;br /&gt;      DataSorted = true&lt;br /&gt;    },&lt;br /&gt;    ...&lt;br /&gt;  );&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Setting &lt;em&gt;DataSorted&lt;/em&gt; to true will cause jqGrid to add grouping column name (name not index) to sorting names (jqGrid requires data sorted by grouping column). There is also new DataAnnotation (&lt;em&gt;JqGridColumnSummary&lt;/em&gt;)available which provides control ower group summary for the column.&lt;/span&gt;&lt;br /&gt;&lt;div style="clear: both" class="separator"&gt;&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" alt="jqGrid grouping" src="http://4.bp.blogspot.com/-aoWR68Gy1l4/Ti8oWJJK_bI/AAAAAAAAAPw/dMXp_nsK3VI/s1600/jqGrid%2BGrouping.png" /&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The sample project can be downloaded &lt;a href="http://tpeczek.codeplex.com/releases/view/62741"&gt;here&lt;/a&gt;, for those of you who whish to work directly with JavaScript the jqGrid in ASP.NET MVC 3 and Razor samples are available &lt;a href="http://tpeczek.codeplex.com/releases/view/61796"&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=yqMjTQi7Mbo:-H7dFVINXho:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=yqMjTQi7Mbo:-H7dFVINXho:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/yqMjTQi7Mbo" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2011/07/jqgrid-strongly-typed-helper-caption.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-kesR4XB3SF0/Ti8mpurOnUI/AAAAAAAAAPg/0cyyf_dRnNQ/s72-c/jqGrid%2BCaption.png" height="72" width="72" /><thr:total>12</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-6596133124313859388</guid><pubDate>Sun, 22 May 2011 22:07:00 +0000</pubDate><atom:updated>2011-05-23T00:07:58.569+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">jquery</category><category domain="http://www.blogger.com/atom/ns#">jqgrid</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><title>jqGrid and ASP.NET MVC – Batch updates</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Recently I've been asked to prepare a batch update scenario for &lt;em&gt;jqGrid&lt;/em&gt;. After playing around with few prototypes I decided use &lt;a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:inline_editing"&gt;inline editing&lt;/a&gt; for that purpose.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;First we need to put all displayed rows into editable state. The best way to do this is to call &lt;em&gt;editRow&lt;/em&gt; for each row during &lt;em&gt;gridComplete&lt;/em&gt; event:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery-1.4.4.min.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery.jqGrid.locale-en-3.8.2.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery.jqGrid-3.8.2.min.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery.json-2.2.min.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;  $(document).ready(function () {&lt;br /&gt;    $('#grid_id').jqGrid({&lt;br /&gt;      //Here you set up colModel, colNames and any other options&lt;br /&gt;      ...&lt;br /&gt;      //This event fires after all the data is loaded into the grid&lt;br /&gt;      gridComplete: function() {&lt;br /&gt;        //Get ids for all current rows&lt;br /&gt;        var dataIds = $('#grid_id').jqGrid('getDataIDs');&lt;br /&gt;        for (var i = 0;i &amp;lt; dataIds.length; i++) {&lt;br /&gt;          //Put row in edit state&lt;br /&gt;          $(&amp;quot;#grid_id&amp;quot;).jqGrid('editRow', dataIds[i], false);&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    });&lt;br /&gt;  });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This way we can be sure, that every row loaded by &lt;em&gt;jqGrid&lt;/em&gt; will end up in edit state. Now we need to add a button which will trigger the batch update. In the &lt;em&gt;click&lt;/em&gt; event of that button we want to save every row to local data array. We can achieve that by using &lt;em&gt;saveRow&lt;/em&gt; method, we just need to put 'clientArray' in third parameter. One important thing to remember here is that &lt;em&gt;saveRow&lt;/em&gt; may throw an exception in case of validation errors - in such a case we will restore the original row and skip sending it to the server. Actual sending will be done by &lt;em&gt;jQuery.ajax()&lt;/em&gt; method:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;$('#button_id').click(function() {&lt;br /&gt;  var batch = new Array();&lt;br /&gt;  //Get ids for all current rows&lt;br /&gt;  var dataIds = $('#grid_id').jqGrid('getDataIDs');&lt;br /&gt;  for (var i = 0; i &amp;lt; dataIds.length; i++) {&lt;br /&gt;    try {&lt;br /&gt;      //Save row only to the grid &lt;br /&gt;      $('#grid_id').jqGrid('saveRow', dataIds[i], false, 'clientArray');&lt;br /&gt;      //Get row data&lt;br /&gt;      var data = $('#grid_id').jqGrid('getRowData', dataIds[i]);&lt;br /&gt;      //Data doesn't contains actual id&lt;br /&gt;      data.Id = dataIds[i];&lt;br /&gt;      //Add data to the batch&lt;br /&gt;      batch.push(data);&lt;br /&gt;    }&lt;br /&gt;    catch (ex) {&lt;br /&gt;      //If you are using editRules it might end up with exception&lt;br /&gt;      $('#grid_id').jqGrid('restoreRow', dataIds[i]);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  //Send batch to the server&lt;br /&gt;  $.ajax({&lt;br /&gt;    type: 'POST',&lt;br /&gt;    contentType: 'application/json; charset=utf-8',&lt;br /&gt;    url: '@Url.Action(&amp;quot;BatchUpdate&amp;quot;, &amp;quot;Home&amp;quot;)',&lt;br /&gt;    dataType: 'json',&lt;br /&gt;    data: $.toJSON(batch),&lt;br /&gt;    success: function(result) {&lt;br /&gt;      ...&lt;br /&gt;      $('#grid_id').trigger('reloadGrid');&lt;br /&gt;    }&lt;br /&gt;  });&lt;br /&gt;});&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we have to receive the data on server side. Thanks to built in JSON model binding in ASP.NET MVC 3 we can do this with very simple action method:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;[AcceptVerbs(HttpVerbs.Post)]&lt;br /&gt;public JsonResult BatchUpdate(List&amp;lt;ViewModel&amp;gt; viewModelsBatch)&lt;br /&gt;{&lt;br /&gt;  //Update your data storage here&lt;br /&gt;  ...&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Feel free to use this solution if you need something like this.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=cuwdqv6VAMM:proYA-6GFt4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=cuwdqv6VAMM:proYA-6GFt4:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/cuwdqv6VAMM" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2011/05/jqgrid-and-aspnet-mvc-batch-updates.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><thr:total>14</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-5003939522566519285</guid><pubDate>Mon, 16 May 2011 20:40:00 +0000</pubDate><atom:updated>2011-05-16T22:42:02.565+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">WebPI</category><category domain="http://www.blogger.com/atom/ns#">authentication</category><category domain="http://www.blogger.com/atom/ns#">proxy</category><title>Making WebPI work with proxy authentica​tion</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Recently I had to use &lt;em&gt;WebPI&lt;/em&gt; on a machine behind a proxy which required authentication. After some time with google all I have found was information, that &lt;em&gt;WebPI&lt;/em&gt; doesn't support authenticated proxies. As I really needed the tool, I decided to try find some workaround.&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;First step was to get the offline installer for &lt;em&gt;WebPI&lt;/em&gt; (it's available &lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=32B0DFE5-F139-4E1C-B412-3DA39F50BBF9"&gt;here&lt;/a&gt;). After installation, the first run attempt resulted in following error:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: plain;"&gt;---------------------------&lt;br /&gt;Microsoft Web Platform Installer&lt;br /&gt;---------------------------&lt;br /&gt;Url 'https://go.microsoft.com/fwlink/?LinkId=193533' returned HTTP status code: 407&lt;br /&gt;---------------------------&lt;br /&gt;OK  &lt;br /&gt;---------------------------&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The 407 error code stands for proxy authentication failure. If you are lucky, all what you need to do is enabling default credentials for proxy authentication. This can be easily done by modifying &lt;em&gt;WebPlatformInstaller.exe.config&lt;/em&gt; file:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;  ...&lt;br /&gt;    &amp;lt;system.net&amp;gt;&lt;br /&gt;      &amp;lt;defaultProxy enabled=&amp;quot;true&amp;quot; useDefaultCredentials=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;    &amp;lt;/system.net&amp;gt;&lt;br /&gt;  ...&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Things are getting a little bit more complicated, when you have to provide specific user and password combination for basic proxy authentication. The &lt;em&gt;defaultProxy&lt;/em&gt; element can have a child element &lt;em&gt;module&lt;/em&gt;, which can be used for adding a new proxy module to application. Such a proxy module is nothing more than a class which implements &lt;em&gt;IWebProxy&lt;/em&gt; interface:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;namespace WebPI.Net&lt;br /&gt;{&lt;br /&gt;  public class AuthenticatedProxy : IWebProxy&lt;br /&gt;  {&lt;br /&gt;    public ICredentials Credentials&lt;br /&gt;    {&lt;br /&gt;      //Put your user name and password into credentials&lt;br /&gt;      get { return new NetworkCredential(&amp;quot;user&amp;quot;, &amp;quot;password&amp;quot;); }&lt;br /&gt;      set { }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Uri GetProxy(Uri destination)&lt;br /&gt;    {&lt;br /&gt;      //Proxy URI will be taken from the current user's IE proxy settings&lt;br /&gt;      return WebRequest.GetSystemWebProxy().GetProxy(destination);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public bool IsBypassed(Uri host)&lt;br /&gt;    {&lt;br /&gt;      return false;&lt;br /&gt;    } &lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The &lt;em&gt;GetSystemWebProxy&lt;/em&gt; method guarantees support for IE proxy settings (automatically detect proxy settings, automatic configuration script, manual proxy server settings and advanced manual proxy server settings). Now only a small change to &lt;em&gt;WebPlatformInstaller.exe.config&lt;/em&gt; file is needed:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;  ...&lt;br /&gt;  &amp;lt;system.net&amp;gt;&lt;br /&gt;    &amp;lt;defaultProxy enabled=&amp;quot;true&amp;quot; useDefaultCredentials=&amp;quot;false&amp;quot;&amp;gt;&lt;br /&gt;      &amp;lt;module type=&amp;quot;WebPI.Net.AuthenticatedProxy, WebPI.Net, Version=1.0.0.0, Culture=neutral, PublicKeyToken=79a8d77199cbf3bc&amp;quot; /&amp;gt;&lt;br /&gt;    &amp;lt;/defaultProxy&amp;gt;&lt;br /&gt;  &amp;lt;/system.net&amp;gt;&lt;br /&gt;  ...&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;That's it. This solution has been tested only on one machine but it has completely resolved the problem of proxy authentication for me, I hope it will do the same for some of you.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=mHeBQ4Xws-w:XR8WhYONi9E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=mHeBQ4Xws-w:XR8WhYONi9E:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/mHeBQ4Xws-w" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2011/05/making-webpi-work-with-proxy.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><thr:total>7</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-8215856002702818502</guid><pubDate>Sun, 27 Mar 2011 16:24:00 +0000</pubDate><atom:updated>2011-03-30T16:54:30.394+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">crud</category><category domain="http://www.blogger.com/atom/ns#">tinymce</category><category domain="http://www.blogger.com/atom/ns#">file upload</category><category domain="http://www.blogger.com/atom/ns#">jqgrid</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><title>jqGrid and ASP.NET MVC – Form Editing with TinyMCE and file upload</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;In one of comments to my &lt;a href="http://tpeczek.blogspot.com/2011/03/jqgrid-and-aspnet-mvc-strongly-typed.html"&gt;jqGrid strongly typed helper&lt;/a&gt; post I was asked for form editing demo with file upload and &lt;a href="http://tinymce.moxiecode.com/"&gt;TinyMCE&lt;/a&gt; integration, so here it comes.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The demo will provide a CRUD functionality for &lt;em&gt;Employees&lt;/em&gt; table from &lt;em&gt;Northwind&lt;/em&gt; database. I will skip &lt;em&gt;Employee&lt;/em&gt; and &lt;em&gt;EmployeesRepository&lt;/em&gt; classes here (full source code for entire sample can be downloaded &lt;a href="http://tpeczek.codeplex.com/releases/view/63305"&gt;here&lt;/a&gt;) and go straight to &lt;em&gt;ViewModel&lt;/em&gt; which will be used by the helper:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;public class EmployeeViewModel&lt;br /&gt;{&lt;br /&gt;  #region Properties&lt;br /&gt;  [ScaffoldColumn(false)]&lt;br /&gt;  public int Id { get; set; }&lt;br /&gt;&lt;br /&gt;  [JqGridColumnSortable(false)]&lt;br /&gt;  [JqGridColumnFormatter(&amp;quot;$.photoFormatter&amp;quot;, UnFormatter = &amp;quot;$.photoUnFormatter&amp;quot;)]&lt;br /&gt;  [JqGridColumnLayout(JqGridAlignments.Center, Width = 35)]&lt;br /&gt;  [JqGridColumnEditable(true, EditType = JqGridColumnEditTypes.File)]&lt;br /&gt;  public string Photo { get; private set; }&lt;br /&gt;&lt;br /&gt;  [StringLength(25)]&lt;br /&gt;  [JqGridColumnSortable(true)]&lt;br /&gt;  [DisplayName(&amp;quot;Title of courtesy&amp;quot;)]&lt;br /&gt;  [JqGridColumnEditable(true, EditType = JqGridColumnEditTypes.Text)]&lt;br /&gt;  public string TitleOfCourtesy { get; set; }&lt;br /&gt;&lt;br /&gt;  [Required]&lt;br /&gt;  [StringLength(10)]&lt;br /&gt;  [DisplayName(&amp;quot;First name&amp;quot;)]&lt;br /&gt;  [JqGridColumnSortable(true)]&lt;br /&gt;  [JqGridColumnEditable(true, EditType = JqGridColumnEditTypes.Text)]&lt;br /&gt;  public string FirstName { get; set; }&lt;br /&gt;&lt;br /&gt;  [Required]&lt;br /&gt;  [StringLength(20)]&lt;br /&gt;  [DisplayName(&amp;quot;Last name&amp;quot;)]&lt;br /&gt;  [JqGridColumnSortable(true)]&lt;br /&gt;  [JqGridColumnEditable(true, EditType = JqGridColumnEditTypes.Text)]&lt;br /&gt;  public string LastName { get; set; }&lt;br /&gt;&lt;br /&gt;  [StringLength(30)]&lt;br /&gt;  [JqGridColumnSortable(true)]&lt;br /&gt;  [JqGridColumnEditable(true, EditType = JqGridColumnEditTypes.Text)]&lt;br /&gt;  public string Title { get; set; }&lt;br /&gt;&lt;br /&gt;  [AllowHtml]&lt;br /&gt;  [JqGridColumnSortable(false)]&lt;br /&gt;  [JqGridColumnLayout(JqGridAlignments.Left, Width = 450)]&lt;br /&gt;  [JqGridColumnEditable(true, EditType = JqGridColumnEditTypes.TextArea)]&lt;br /&gt;  public string Notes { get; set; }&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region Constructors&lt;br /&gt;  public EmployeeViewModel()&lt;br /&gt;  { }&lt;br /&gt;&lt;br /&gt;  public EmployeeViewModel(Employee employee)&lt;br /&gt;  {&lt;br /&gt;    this.Id = employee.Id;&lt;br /&gt;    this.TitleOfCourtesy = employee.TitleOfCourtesy;&lt;br /&gt;    this.FirstName = employee.FirstName;&lt;br /&gt;    this.LastName = employee.LastName;&lt;br /&gt;    this.Title = employee.Title;&lt;br /&gt;    this.Notes = employee.Notes;&lt;br /&gt;&lt;br /&gt;    RouteValueDictionary photoUrlRouteData = new RouteValueDictionary();&lt;br /&gt;    photoUrlRouteData[&amp;quot;controller&amp;quot;] = &amp;quot;Home&amp;quot;;&lt;br /&gt;    photoUrlRouteData[&amp;quot;action&amp;quot;] = &amp;quot;EmployeePhoto&amp;quot;;&lt;br /&gt;    photoUrlRouteData[&amp;quot;id&amp;quot;] = employee.Id;&lt;br /&gt;    Photo = RouteTable.Routes.GetVirtualPathForArea(HttpContext.Current != null ? HttpContext.Current.Request.RequestContext : null, null, photoUrlRouteData).VirtualPath;&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;That's a lot of attributes, but we will focus only on two properties - &lt;em&gt;Photo&lt;/em&gt; for which we want file upload functionality and &lt;em&gt;Notes&lt;/em&gt; which we want to integrate with &lt;em&gt;TinyMCE&lt;/em&gt;. We will start with &lt;em&gt;Notes&lt;/em&gt;. Two most important attributes here are &lt;em&gt;AllowHtml&lt;/em&gt; (so TinyMCE can post some HTML for this property) and &lt;em&gt;JqGridColumnEditable&lt;/em&gt; (we want jqGrid to generate a TextArea for us, so we can attach TinyMCE to it). The only problem with TinyMCE here is that it can't be attached to an element which is not visible. Because of that we have to recreate it every time the form is displayed. There are two events in jqGrid navigator action options, which will allow us to do it easily: &lt;em&gt;afterShowForm&lt;/em&gt; and &lt;em&gt;onClose&lt;/em&gt;. Here goes the JavaScript functions for those events:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;$.onAfterShowForm = function(formSelector) {&lt;br /&gt;  //Add TinyMCE editor instance&lt;br /&gt;  $('textarea', formSelector).attr('cols', '50').attr('rows', '15').tinymce({&lt;br /&gt;    theme : 'advanced',&lt;br /&gt;    theme_advanced_toolbar_location : 'top'&lt;br /&gt;  });&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;$.onClose = function(formSelector) {&lt;br /&gt;  //Remove TinyMCE editor instance&lt;br /&gt;  $('textarea', formSelector).tinymce().remove();&lt;br /&gt;};&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;So TinyMCE is working, what about the file upload? We can set the &lt;em&gt;edittype&lt;/em&gt; to file and than proper input element will be created by jqGrid, but this is where the support ends - jqGrid will not post the file for us. Tony Tomov &lt;a href="http://www.trirand.com/blog/?page_id=393/feature-request/file-upload-again/"&gt;suggests&lt;/a&gt; creating an additional submit button for this, but this way you need to post data in two steps. I really wanted to have all data posted at once, so I decided to go a little bit &amp;quot;hacky&amp;quot; here. Please be aware, that following solution &lt;strong&gt;will completely replace jqGrid built in post functionality&lt;/strong&gt; - if you need any part of it, you need to write it yourself here. I'm going to use &lt;a href="http://www.jainaewen.com/files/javascript/jquery/iframe-post-form/"&gt;Ajax File Uploader&lt;/a&gt; plugin, to post entire form at once. To achieve this I will change some of the form attributes in &lt;em&gt;onInitializeForm&lt;/em&gt; event:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;//WARNING: This will completely replace build in jqGrid post behavior&lt;br /&gt;$.onInitializeForm = function(formSelector) {&lt;br /&gt;  //Set enctype='multipart/form-data'&lt;br /&gt;  $(formSelector).attr('enctype', 'multipart/form-data')&lt;br /&gt;                 //method='POST'&lt;br /&gt;                 .attr('method', 'POST')&lt;br /&gt;                 //remove onsubmit&lt;br /&gt;                 .removeAttr('onsubmit')&lt;br /&gt;                 //attach Ajax File Uploader plugin&lt;br /&gt;                 .iframePostForm({&lt;br /&gt;                   //When post request is completed&lt;br /&gt;                   complete: function(response) {&lt;br /&gt;                     //check if operation was successful&lt;br /&gt;                     if(response != 'success') {&lt;br /&gt;                       //if not, then display error message&lt;br /&gt;                    $('#FormError&amp;gt;td', formSelector).html(response);&lt;br /&gt;                    $('#FormError', formSelector).show();&lt;br /&gt;                     } else {&lt;br /&gt;                       var id = $('#id_g', formSelector).val();&lt;br /&gt;                       //if yes, reload jqGrid&lt;br /&gt;                       $('#employees').trigger('reloadGrid');&lt;br /&gt;                       //and restore current selection&lt;br /&gt;                       setTimeout(function(){&lt;br /&gt;                         $('#employees').jqGrid('setSelection', id);&lt;br /&gt;                       }, 1000);&lt;br /&gt;                     }&lt;br /&gt;                     //Remove class from submit button&lt;br /&gt;                     $('#iframe_submit').removeClass('ui-state-active');&lt;br /&gt;                   }&lt;br /&gt;                 });&lt;br /&gt;  //Create inputs for 'id' and 'oper' keys which jqGrid adds to request by default&lt;br /&gt;  $('#id_g', formSelector).after($('&amp;lt;input /&amp;gt;').attr('id', 'iframe_id').attr('type', 'text').attr('name', 'id'));&lt;br /&gt;  $('#id_g', formSelector).after($('&amp;lt;input /&amp;gt;').attr('id', 'iframe_oper').attr('type', 'text').attr('name', 'oper'));&lt;br /&gt;  //Change the submit button id, so jqGrid will not attach its click event&lt;br /&gt;  $('#sData').attr('id', 'iframe_submit')&lt;br /&gt;             //and attach our click event&lt;br /&gt;             .click(function(e) {&lt;br /&gt;               //When user clicks the submit button hide error message&lt;br /&gt;               $('#FormError', formSelector).hide();&lt;br /&gt;               var id = $('#id_g', formSelector).val();&lt;br /&gt;               //set values for 'id' and 'oper' inputs&lt;br /&gt;               $('#iframe_id', formSelector).val(id);&lt;br /&gt;               $('#iframe_oper', formSelector).val((id == '_empty') ? 'add' : 'edit');&lt;br /&gt;               //set action url based on operation type&lt;br /&gt;               $(formSelector).attr('action', (id == '_empty') ? '@Url.Action(&amp;quot;InsertEmployee&amp;quot;)' : '@Url.Action(&amp;quot;UpdateEmployee&amp;quot;)')&lt;br /&gt;               //add class to submit button&lt;br /&gt;               $('#iframe_submit').addClass('ui-state-active');&lt;br /&gt;               //and submit form&lt;br /&gt;               $(formSelector).submit();&lt;br /&gt;               return false;&lt;br /&gt;  });&lt;br /&gt;};&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we can create the view. First we should instantiate jqGrid helper with all the desired options:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;@{&lt;br /&gt;  ViewBag.Title = &amp;quot;jqGrid in ASP.NET MVC - Employees [Form Editing]&amp;quot;;&lt;br /&gt;&lt;br /&gt;  var grid = new Lib.Web.Mvc.JQuery.JqGrid.JqGridHelper&amp;lt;jqGrid.DungDepTrai.Models.EmployeeViewModel&amp;gt;(&amp;quot;employees&amp;quot;,&lt;br /&gt;    dataType: Lib.Web.Mvc.JQuery.JqGrid.JqGridDataTypes.Json,&lt;br /&gt;    methodType: Lib.Web.Mvc.JQuery.JqGrid.JqGridMethodTypes.Post,&lt;br /&gt;    pager: true,&lt;br /&gt;    rowsNumber: 10,&lt;br /&gt;    sortingName: &amp;quot;LastName&amp;quot;,&lt;br /&gt;    sortingOrder: Lib.Web.Mvc.JQuery.JqGrid.JqGridSortingOrders.Asc,&lt;br /&gt;    url: Url.Action(&amp;quot;FindEmployees&amp;quot;),&lt;br /&gt;    width: 1077,&lt;br /&gt;    viewRecords: true&lt;br /&gt;  ).Navigator(new Lib.Web.Mvc.JQuery.JqGrid.JqGridNavigatorOptions() { Search = false, View = false },&lt;br /&gt;    editActionOptions: new Lib.Web.Mvc.JQuery.JqGrid.JqGridNavigatorActionOptions() { Url = Url.Action(&amp;quot;UpdateEmployee&amp;quot;), OnInitializeForm = &amp;quot;$.onInitializeForm&amp;quot;, OnAfterShowForm = &amp;quot;$.onAfterShowForm&amp;quot;, OnClose = &amp;quot;$.onClose&amp;quot; },&lt;br /&gt;    addActionOptions: new Lib.Web.Mvc.JQuery.JqGrid.JqGridNavigatorActionOptions() { Url = Url.Action(&amp;quot;InsertEmployee&amp;quot;), OnInitializeForm = &amp;quot;$.onInitializeForm&amp;quot;, OnAfterShowForm = &amp;quot;$.onAfterShowForm&amp;quot;, OnClose = &amp;quot;$.onClose&amp;quot; },&lt;br /&gt;    deleteActionOptions: new Lib.Web.Mvc.JQuery.JqGrid.JqGridNavigatorActionOptions() { Url = Url.Action(&amp;quot;DeleteEmployee&amp;quot;) }&lt;br /&gt;  );&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Then we can get required HTML out of it:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;@grid.GetHtml()&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;And add the JavaScript:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery-1.4.4.min.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery.jqGrid.locale-en-3.8.2.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery.jqGrid-3.8.2.min.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery.iframe-post-form.min.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/TinyMCE/tiny_mce.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/TinyMCE/jquery.tinymce.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;  $(document).ready(function () {&lt;br /&gt;    @grid.GetJavaScript()&lt;br /&gt;  });&lt;br /&gt;&lt;br /&gt;  //Every photo have constant URL, this formatter will make them refresh at every reload &amp;lt;-- only for presentation purposes&lt;br /&gt;  $.photoFormatter = function(cellvalue, options, rowObject) {&lt;br /&gt;    return &amp;quot;&amp;lt;img style='width:25px' src='&amp;quot; + cellvalue + &amp;quot;&amp;amp;rand=&amp;quot; + (Math.random() * 10000000) + &amp;quot;' /&amp;gt;&amp;quot;;&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;  //Always unformat photo as empty value&lt;br /&gt;  $.photoUnFormatter = function(cellvalue, options, cellobject) {&lt;br /&gt;    return '';&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;  //WARNING: This will completely replace build in jqGrid post behavior&lt;br /&gt;  $.onInitializeForm = function(formSelector) {&lt;br /&gt;    ...&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;  $.onAfterShowForm = function(formSelector) {&lt;br /&gt;    ...&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;  $.onClose = function(formSelector) {&lt;br /&gt;    ...&lt;br /&gt;  };&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The only thing that is missing here is some server side code for handling the requests:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;public ViewResult Employees()&lt;br /&gt;{&lt;br /&gt;  return View();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[AcceptVerbs(HttpVerbs.Post)]&lt;br /&gt;public ActionResult FindEmployees(JqGridRequest request)&lt;br /&gt;{&lt;br /&gt;  int totalRecordsCount = _employeesRepository.GetCount();&lt;br /&gt;&lt;br /&gt;  JqGridResponse response = new JqGridResponse()&lt;br /&gt;  {&lt;br /&gt;    TotalPagesCount = (int)Math.Ceiling((float)totalRecordsCount / (float)request.RecordsCount),&lt;br /&gt;    PageIndex = request.PageIndex,&lt;br /&gt;    TotalRecordsCount = totalRecordsCount&lt;br /&gt;  };&lt;br /&gt;  response.Records.AddRange(from employee in _employeesRepository.FindRange(String.Format(&amp;quot;{0} {1}&amp;quot;, request.SortingName, request.SortingOrder), request.PageIndex * request.RecordsCount, request.RecordsCount)&lt;br /&gt;                            select new JqGridRecord&amp;lt;EmployeeViewModel&amp;gt;(Convert.ToString(employee.Id), new EmployeeViewModel(employee)));&lt;br /&gt;&lt;br /&gt;  return new JqGridJsonResult() { Data = response };&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[NoCache]&lt;br /&gt;public ActionResult EmployeePhoto(int id)&lt;br /&gt;{&lt;br /&gt;  //We should keep images in file system&lt;br /&gt;  string employeePhotoPath = GetEmployeePhotoPath(id);&lt;br /&gt;  if (!System.IO.File.Exists(employeePhotoPath))&lt;br /&gt;  {&lt;br /&gt;    Employee employee = _employeesRepository.FindByKey(id);&lt;br /&gt;    if (employee.Photo != null)&lt;br /&gt;    {&lt;br /&gt;      using (FileStream employeePhotoStream = new FileStream(employeePhotoPath, FileMode.Create, FileAccess.Write))&lt;br /&gt;        //Skip Ole bytes array&lt;br /&gt;        employeePhotoStream.Write(employee.Photo, 78, employee.Photo.Length - 78);&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;      //You might want to return some default image here&lt;br /&gt;      return new EmptyResult();&lt;br /&gt;  }&lt;br /&gt;  return File(employeePhotoPath, &amp;quot;image/bmp&amp;quot;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[AcceptVerbs(HttpVerbs.Post)]&lt;br /&gt;public ContentResult InsertEmployee([Bind(Exclude = &amp;quot;Id&amp;quot;)]EmployeeViewModel viewModel, HttpPostedFileBase photo)&lt;br /&gt;{&lt;br /&gt;  if (ModelState.IsValid)&lt;br /&gt;  {&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;      if (photo != null &amp;amp;&amp;amp; photo.ContentLength &amp;gt; 0 &amp;amp;&amp;amp; photo.ContentType != &amp;quot;image/bmp&amp;quot;)&lt;br /&gt;        return Content(&amp;quot;Photo must be in BMP format.&amp;quot;);&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;        Employee employee = new Employee();&lt;br /&gt;        employee.LastName = viewModel.LastName;&lt;br /&gt;        employee.Notes = viewModel.Notes;&lt;br /&gt;        employee.Title = viewModel.Title;&lt;br /&gt;        employee.TitleOfCourtesy = viewModel.TitleOfCourtesy;&lt;br /&gt;        employee.FirstName = viewModel.FirstName;&lt;br /&gt;        _employeesRepository.Add(ref employee);&lt;br /&gt;&lt;br /&gt;        _employeesRepository.SaveChanges();&lt;br /&gt;&lt;br /&gt;        photo.SaveAs(GetEmployeePhotoPath(employee.Id));&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    catch&lt;br /&gt;    {&lt;br /&gt;      //There should be some decent exception handling here&lt;br /&gt;      return Content(&amp;quot;An error occurred during employee insert.&amp;quot;);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return Content(&amp;quot;success&amp;quot;);&lt;br /&gt;  }&lt;br /&gt;  else&lt;br /&gt;    return Content(&amp;quot;Invalid employee data.&amp;quot;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[AcceptVerbs(HttpVerbs.Post)]&lt;br /&gt;public ContentResult UpdateEmployee(EmployeeViewModel viewModel, HttpPostedFileBase photo)&lt;br /&gt;{&lt;br /&gt;  if (ModelState.IsValid)&lt;br /&gt;  {&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;      Employee employee = _employeesRepository.FindByKey(viewModel.Id);&lt;br /&gt;      if (employee != null)&lt;br /&gt;      {&lt;br /&gt;        if (photo != null &amp;amp;&amp;amp; photo.ContentLength &amp;gt; 0)&lt;br /&gt;        {&lt;br /&gt;          if (photo.ContentType == &amp;quot;image/bmp&amp;quot;)&lt;br /&gt;            photo.SaveAs(GetEmployeePhotoPath(viewModel.Id));&lt;br /&gt;          else&lt;br /&gt;            return Content(&amp;quot;Photo must be in BMP format.&amp;quot;);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        employee.LastName = viewModel.LastName;&lt;br /&gt;        employee.Notes = viewModel.Notes;&lt;br /&gt;        employee.Title = viewModel.Title;&lt;br /&gt;        employee.TitleOfCourtesy = viewModel.TitleOfCourtesy;&lt;br /&gt;        employee.FirstName = viewModel.FirstName;&lt;br /&gt;&lt;br /&gt;        _employeesRepository.SaveChanges();&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;        return Content(&amp;quot;Couldn't found employee for update.&amp;quot;);&lt;br /&gt;    }&lt;br /&gt;    catch&lt;br /&gt;    {&lt;br /&gt;      //There should be some decent exception handling here&lt;br /&gt;      return Content(&amp;quot;An error occurred during employee update.&amp;quot;);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return Content(&amp;quot;success&amp;quot;);&lt;br /&gt;  }&lt;br /&gt;  else&lt;br /&gt;    return Content(&amp;quot;Invalid employee data.&amp;quot;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[AcceptVerbs(HttpVerbs.Post)]&lt;br /&gt;public HttpStatusCodeResult DeleteEmployee(int id)&lt;br /&gt;{&lt;br /&gt;  try&lt;br /&gt;  {&lt;br /&gt;    _employeesRepository.Delete(id);&lt;br /&gt;    _employeesRepository.SaveChanges();&lt;br /&gt;&lt;br /&gt;    return new HttpStatusCodeResult(200, &amp;quot;Succeeded&amp;quot;);&lt;br /&gt;  }&lt;br /&gt;  catch&lt;br /&gt;  {&lt;br /&gt;    //There should be some decent exception handling here&lt;br /&gt;    return new HttpStatusCodeResult(500, &amp;quot;An error occurred during employee delete.&amp;quot;);&lt;br /&gt;  }    &lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we can play with the demo.&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://1.bp.blogspot.com/-Ywlwdfocnnk/TY9U3LyPMaI/AAAAAAAAAOQ/aUYxTTaoPeI/s1600/jqGridTinyMCE.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-Ywlwdfocnnk/TY9U3LyPMaI/AAAAAAAAAOQ/aUYxTTaoPeI/s320/jqGridTinyMCE.jpg" width="320" height="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;I hope you will find it helpful.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=Ub_apqUd7ss:LxHnc0Vmhu0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=Ub_apqUd7ss:LxHnc0Vmhu0:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/Ub_apqUd7ss" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2011/03/jqgrid-and-aspnet-mvc-form-editing-with.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-Ywlwdfocnnk/TY9U3LyPMaI/AAAAAAAAAOQ/aUYxTTaoPeI/s72-c/jqGridTinyMCE.jpg" height="72" width="72" /><thr:total>15</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-7773942381297818679</guid><pubDate>Thu, 17 Mar 2011 19:40:00 +0000</pubDate><atom:updated>2011-03-31T14:30:02.660+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">jquery</category><category domain="http://www.blogger.com/atom/ns#">helper</category><category domain="http://www.blogger.com/atom/ns#">jqgrid</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><title>jqGrid and ASP.NET MVC - Strongly typed helper</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;I've been using &lt;a href="http://www.trirand.com/blog/"&gt;jqGrid&lt;/a&gt; a lot over last year. During this time I have created many helper classes for it. Recently I decided to put all those classes together, clean up, rewrite and publish for the community.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;I made helper available as part of my &lt;em&gt;Lib.Web.Mvc&lt;/em&gt; library, and you can download it &lt;a href="http://tpeczek.codeplex.com/releases/view/63274"&gt;here&lt;/a&gt; (source code included), or go for the &lt;em&gt;NuGet&lt;/em&gt; package.&lt;/span&gt;&lt;div style="text-align: center; clear: both;" class="separator"&gt;&lt;img border="0" style="border: none" src="http://3.bp.blogspot.com/-rF_BKvDLaeA/TYJgI6fb7aI/AAAAAAAAANg/xXYpsvT2PP4/s1600/lib-web-mvc-nuget.png" /&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now let me show you simple usage example. We will need a model class for our grid:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;public class ProductViewModel&lt;br /&gt;{&lt;br /&gt;  #region Properties&lt;br /&gt;  public int Id { get; set; }&lt;br /&gt;&lt;br /&gt;  public string Name { get; set; }&lt;br /&gt;&lt;br /&gt;  [JqGridColumnSortingName(&amp;quot;SupplierId&amp;quot;)]&lt;br /&gt;  public string Supplier { get; set; }&lt;br /&gt;&lt;br /&gt;  [JqGridColumnSortingName(&amp;quot;CategoryId&amp;quot;)]&lt;br /&gt;  public string Category { get; set; }&lt;br /&gt;&lt;br /&gt;  [DisplayName(&amp;quot;Quantity Per Unit&amp;quot;)]&lt;br /&gt;  [JqGridColumnAlign(JqGridColumnAligns.Center)]&lt;br /&gt;  public string QuantityPerUnit { get; set; }&lt;br /&gt;&lt;br /&gt;  [DisplayName(&amp;quot;Unit Price&amp;quot;)]&lt;br /&gt;  [JqGridColumnAlign(JqGridColumnAligns.Center)]&lt;br /&gt;  public decimal? UnitPrice { get; set; }&lt;br /&gt;&lt;br /&gt;  [DisplayName(&amp;quot;Units In Stock&amp;quot;)]&lt;br /&gt;  [JqGridColumnAlign(JqGridColumnAligns.Center)]&lt;br /&gt;  public short? UnitsInStock { get; set; }&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region Constructor&lt;br /&gt;  public ProductViewModel()&lt;br /&gt;  { }&lt;br /&gt;&lt;br /&gt;  public ProductViewModel(Product product)&lt;br /&gt;  {&lt;br /&gt;    this.Id = product.Id;&lt;br /&gt;    this.Name = product.Name;&lt;br /&gt;    this.Supplier = product.Supplier.Name;&lt;br /&gt;    this.Category = product.Category.Name;&lt;br /&gt;    this.QuantityPerUnit = product.QuantityPerUnit;&lt;br /&gt;    this.UnitPrice = product.UnitPrice;&lt;br /&gt;    this.UnitsInStock = product.UnitsInStock;&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Following standard &lt;em&gt;DataAnnotations&lt;/em&gt; attributes are supported:&lt;ul&gt;&lt;li&gt;&lt;strong&gt;DisplayName&lt;/strong&gt; - This will set the name for the column (default is property name).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DisplayFormat&lt;/strong&gt; - Value set for &lt;em&gt;NullDisplayText&lt;/em&gt; will be used as cell value if property value will be null. Value set for &lt;em&gt;DataFormatString&lt;/em&gt; will be used for formatting property value (on server side).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;HiddenInput&lt;/strong&gt; - This will set &lt;em&gt;JqGridColumnModel.Hidden&lt;/em&gt; to true.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Range&lt;/strong&gt; - Value set for &lt;em&gt;Maximum&lt;/em&gt; will be used for &lt;em&gt;EditRules.MaxValue&lt;/em&gt; of editable column and value set &lt;em&gt;Minimum&lt;/em&gt; for will be used for &lt;em&gt;EditRules.MinValue&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Required&lt;/strong&gt; - This will set &lt;em&gt;EditRules.Required&lt;/em&gt; to true for editable column.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ScaffoldColumn&lt;/strong&gt; - If set &lt;em&gt;Scaffold&lt;/em&gt; to false, there will be no column created for property with this attribute.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;StringLength&lt;/strong&gt; - Value set for &lt;em&gt;MaximumLength&lt;/em&gt; will be used for &lt;em&gt;EditOptions.MaximumLength&lt;/em&gt; of editable column.&lt;/li&gt;&lt;/ul&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Additionaly the helper support those custom attributes (from &lt;em&gt;Lib.Web.Mvc.JQuery.JqGrid.DataAnnotations&lt;/em&gt; namespace):&lt;ul&gt;&lt;li&gt;&lt;strong&gt;JqGridColumnLayout&lt;/strong&gt; - This will set the layout attributes for the column (alignment, initial width etc.).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;JqGridColumnSortable&lt;/strong&gt; - This will set the sorting options for the column (by default every column is sortable with property name as sorting name).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;JqGridColumnFormatter&lt;/strong&gt; - This will set the predefined (with options) or custom formatter for the column.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;JqGridColumnEditable&lt;/strong&gt; - This will set the edit options for the column.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;JqGridColumnSearchable&lt;/strong&gt; - This will set the search options for the column.&lt;/li&gt;&lt;/ul&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;When our model class is done, we can start creating the view. First we need to include some CSS and JavaScript files:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;link href=&amp;quot;@Url.Content(&amp;quot;~/Content/themes/base/jquery-ui.css&amp;quot;)&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;link href=&amp;quot;@Url.Content(&amp;quot;~/Content/jqGrid/jquery-ui-jqgrid.css&amp;quot;)&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery-1.4.4.min.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery.jqGrid.locale-en-3.8.2.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery.jqGrid-3.8.2.min.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Then we can instantiate the helper and set desired options:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;@{&lt;br /&gt;  var grid = new Lib.Web.Mvc.JQuery.JqGrid.JqGridHelper&amp;lt;jqGrid.Models.ProductViewModel&amp;gt;(&amp;quot;products&amp;quot;,&lt;br /&gt;    dataType: Lib.Web.Mvc.JQuery.JqGrid.JqGridDataTypes.Json,&lt;br /&gt;    methodType: Lib.Web.Mvc.JQuery.JqGrid.JqGridMethodTypes.Post,&lt;br /&gt;    pager: true,&lt;br /&gt;    rowsNumber: 10,&lt;br /&gt;    sortingName: &amp;quot;Id&amp;quot;,&lt;br /&gt;    sortingOrder: Lib.Web.Mvc.JQuery.JqGrid.JqGridSortingOrders.Asc,&lt;br /&gt;    url: Url.Action(&amp;quot;Products&amp;quot;),&lt;br /&gt;    viewRecords: true&lt;br /&gt;  );&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This instance can be used for rendering HTML and JavaScript required by &lt;em&gt;jqGrid&lt;/em&gt;:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;br /&gt;      &lt;pre class="brush: js;"&gt;@grid.GetHtml()&lt;br /&gt;...&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;  $(document).ready(function () {&lt;br /&gt;    @grid.GetJavaScript()&lt;br /&gt;  });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;All we have to do now is creating an action method, which will provide data for our grid:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;[AcceptVerbs(HttpVerbs.Post)]&lt;br /&gt;public ActionResult Products(JqGridRequest request)&lt;br /&gt;{&lt;br /&gt;  int totalRecordsCount = _productsRepository.GetCount();&lt;br /&gt;&lt;br /&gt;  JqGridResponse response = new JqGridResponse()&lt;br /&gt;  {&lt;br /&gt;    TotalPagesCount = (int)Math.Ceiling((float)totalRecordsCount / (float)request.RecordsCount),&lt;br /&gt;    PageIndex = request.PageIndex,&lt;br /&gt;    TotalRecordsCount = totalRecordsCount&lt;br /&gt;  };&lt;br /&gt;  response.Records.AddRange(from product in _productsRepository.FindRange(String.Format(&amp;quot;{0} {1}&amp;quot;, request.SortingName, request.SortingOrder), request.PageIndex * request.RecordsCount, request.RecordsCount)&lt;br /&gt;                            select new JqGridRecord&amp;lt;ProductViewModel&amp;gt;(Convert.ToString(product.Id), new ProductViewModel(product)));&lt;br /&gt;&lt;br /&gt;  return new JqGridJsonResult() { Data= response };&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;When you run it, you should see something similar to this:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://1.bp.blogspot.com/-Bq9mKqO4v84/TXdeFlbFxqI/AAAAAAAAANY/UWnJ6uggc58/s1600/jqGridHelper.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-Bq9mKqO4v84/TXdeFlbFxqI/AAAAAAAAANY/UWnJ6uggc58/s320/jqGridHelper.jpg" width="320" height="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;You can download a &lt;a href="http://tpeczek.codeplex.com/releases/view/62741"&gt;sample project&lt;/a&gt; for this helper, which contains following examples:&lt;ul&gt;&lt;li&gt;Basics &amp;amp; Formatting&lt;/li&gt;&lt;li&gt;Configuration Import/Export&lt;/li&gt;&lt;li&gt;Cell Editing&lt;/li&gt;&lt;li&gt;CRUD - Inline Editing&lt;/li&gt;&lt;li&gt;CRUD - Form Editing&lt;/li&gt;&lt;li&gt;Searching - Single&lt;/li&gt;&lt;li&gt;Searching - Toolbar&lt;/li&gt;&lt;li&gt;Searching - Custom&lt;/li&gt;&lt;li&gt;Searching - Advanced&lt;/li&gt;&lt;li&gt;Subgrid&lt;/li&gt;&lt;li&gt;TreeGrid&lt;/li&gt;&lt;/ul&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The helper doesn't support all the functionality of jqGrid, it's just a compilation of what I've been using. There is also no roadmap for it at the moment. If you find some necessary for you features missing or discover some bugs, please create an issue &lt;a href="http://tpeczek.codeplex.com/WorkItem/Create"&gt;here&lt;/a&gt;. I will continue to develop this helper if the community will find it useful.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=N5V1NiLOrV8:Ir9tMtnGAWE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=N5V1NiLOrV8:Ir9tMtnGAWE:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/N5V1NiLOrV8" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2011/03/jqgrid-and-aspnet-mvc-strongly-typed.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-rF_BKvDLaeA/TYJgI6fb7aI/AAAAAAAAANg/xXYpsvT2PP4/s72-c/lib-web-mvc-nuget.png" height="72" width="72" /><thr:total>72</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-6652950472788484742</guid><pubDate>Mon, 14 Feb 2011 14:55:00 +0000</pubDate><atom:updated>2011-03-31T10:41:40.865+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">jquery</category><category domain="http://www.blogger.com/atom/ns#">grid</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><category domain="http://www.blogger.com/atom/ns#">jquery ui</category><title>An early look at jQuery UI Grid in ASP.NET MVC - Data Model</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;More than a week ago &lt;em&gt;The jQuery UI Team&lt;/em&gt; has &lt;a href="http://blog.jqueryui.com/2011/02/unleash-the-grid/"&gt;announced&lt;/a&gt; that they are building a grid widget. Don't get me wrong, I'm a huge fan of &lt;em&gt;jqGrid&lt;/em&gt; but when jQuery UI will have its own widget I will strongly consider switching. That's why I decided to test the widget through some basic samples while it's being developed.&lt;/span&gt;  &lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;I have downloaded current widget sources from &lt;em&gt;jQuery UI&lt;/em&gt; &lt;a href="https://github.com/jquery/jquery-ui/tree/grid"&gt;grid branch&lt;/a&gt; at GitHub. The widget development takes place in three subfolders: &lt;em&gt;grid-datamodel&lt;/em&gt;, &lt;em&gt;grid-markup&lt;/em&gt; and &lt;em&gt;grid-type&lt;/em&gt; - in this post I will look only into the first one.&lt;/span&gt;   &lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Lets start by referencing some CSS and JavaScript:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;   &lt;pre class="brush: xml;"&gt;&amp;lt;link href=&amp;quot;@Url.Content(&amp;quot;~/Content/site.css&amp;quot;)&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;link href=&amp;quot;@Url.Content(&amp;quot;~/Content/themes/base/jquery-ui.css&amp;quot;)&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;link href=&amp;quot;@Url.Content(&amp;quot;~/Content/grid-datamodel.css&amp;quot;)&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery-1.4.4.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/jquery.tmpl.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/ui/jquery.ui.core.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/ui/jquery.ui.widget.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/datamodel/dataitem.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/datamodel/datasource.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/datamodel/extractor-datasource.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/datamodel/datastore.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;@Url.Content(&amp;quot;~/Scripts/datamodel/grid.js&amp;quot;)&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we will add a table, which will be extended by the widget:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;table id=&amp;quot;products&amp;quot;&amp;gt;&lt;br /&gt;  &amp;lt;thead&amp;gt;&lt;br /&gt;    &amp;lt;tr&amp;gt;&lt;br /&gt;      &amp;lt;th data-field=&amp;quot;ProductID&amp;quot;&amp;gt;Product Id&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th data-field=&amp;quot;ProductName&amp;quot;&amp;gt;Product Name&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th data-field=&amp;quot;Supplier&amp;quot;&amp;gt;Supplier&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th data-field=&amp;quot;Category&amp;quot;&amp;gt;Category&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th data-field=&amp;quot;QuantityPerUnit&amp;quot;&amp;gt;Quantity Per Unit&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th data-field=&amp;quot;UnitPrice&amp;quot;&amp;gt;Unit Price&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th data-field=&amp;quot;UnitsInStock&amp;quot;&amp;gt;Units In Stock&amp;lt;/th&amp;gt;&lt;br /&gt;    &amp;lt;/tr&amp;gt;&lt;br /&gt;  &amp;lt;/thead&amp;gt;&lt;br /&gt;  &amp;lt;tbody&amp;gt;&lt;br /&gt;  &amp;lt;/tbody&amp;gt;&lt;br /&gt;&amp;lt;/table&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Moving on to JavaScript we should define &lt;em&gt;datasource&lt;/em&gt; for the widget. The widget can work with local &lt;em&gt;datasource&lt;/em&gt;, but I will go for a remote one, because this is much more fun ;).&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;//extend dataitem with our new type&lt;br /&gt;$.ui.dataitem.extend('product', {});&lt;br /&gt;&lt;br /&gt;//create datasource for our new type&lt;br /&gt;$.ui.datasource({&lt;br /&gt;  type: 'product',&lt;br /&gt;  source: function (request, response) {&lt;br /&gt;    $.getJSON('@Url.Action(&amp;quot;Products&amp;quot;, &amp;quot;Home&amp;quot;)', request, response);&lt;br /&gt;  }&lt;br /&gt;});&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;At the moment &lt;em&gt;datasource&lt;/em&gt; accepts data as an array of objects, so this simple action will be enough for sending data to the client:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;public JsonResult Products()&lt;br /&gt;{&lt;br /&gt;  object[] products = (from product in _productsRepository.GetProducts()&lt;br /&gt;                       select new&lt;br /&gt;                       {&lt;br /&gt;                         ProductID = product.ProductID,&lt;br /&gt;                         ProductName = product.ProductName,&lt;br /&gt;                         Supplier = product.Supplier.CompanyName,&lt;br /&gt;                         Category = product.Category.CategoryName,&lt;br /&gt;                         QuantityPerUnit = product.QuantityPerUnit,&lt;br /&gt;                         UnitPrice = product.UnitPrice,&lt;br /&gt;                         UnitsInStock = product.UnitsInStock&lt;br /&gt;                       }).ToArray();&lt;br /&gt;&lt;br /&gt;  return Json(products, JsonRequestBehavior.AllowGet);&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;All what is left for use is to apply the widget on our table. While doing this, we must tell the widget how to map objects fields into cells. There are two ways of doing it. We can pass an array of fields names for columns like this:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;$('#products').grid({&lt;br /&gt;  type: 'product',&lt;br /&gt;  columns: [ 'ProductID', 'ProductName', 'Supplier', 'Category', 'QuantityPerUnit', 'UnitPrice', 'UnitsInStock' ]&lt;br /&gt;});&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Or tell the widget to use a row template:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;$('#products').grid({&lt;br /&gt;  type: 'product',&lt;br /&gt;  rowTemplate: $('#products-row-tmpl').html()&lt;br /&gt;});&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;In second case, we have to create a row template with &lt;a href="http://api.jquery.com/category/plugins/templates/"&gt;jQuery Templates plugin&lt;/a&gt;:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;script type=&amp;quot;text/x-jquery-tmpl&amp;quot; id=&amp;quot;products-row-tmpl&amp;quot;&amp;gt;&lt;br /&gt;  &amp;lt;tr&amp;gt;&lt;br /&gt;    &amp;lt;td&amp;gt;${ProductID}&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;td&amp;gt;${ProductName}&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;td&amp;gt;${Supplier}&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;td&amp;gt;${Category}&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;td&amp;gt;${QuantityPerUnit}&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;td&amp;gt;${UnitPrice}&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;td&amp;gt;${UnitsInStock}&amp;lt;/td&amp;gt;&lt;br /&gt;  &amp;lt;/tr&amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;And this is all. The widget will pull the data from the server and render a nice grid for us:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://2.bp.blogspot.com/-BrMz0ofs7QA/TVk9-QcdhMI/AAAAAAAAAIU/bzX0HBbtpN8/s1600/jQueryUIGrid.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-BrMz0ofs7QA/TVk9-QcdhMI/AAAAAAAAAIU/bzX0HBbtpN8/s320/jQueryUIGrid.jpg" width="320" height="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;You can download source code of this sample from my &lt;a href="https://tpeczek.svn.codeplex.com/svn/trunk/MVC/jQuery%20UI%20Grid%20Examples/"&gt;svn repository&lt;/a&gt; at CodePlex. I will continue to play around with this widget as the beginning is very promising.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=YQzyNA3C820:I6AX76RZEG0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=YQzyNA3C820:I6AX76RZEG0:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/YQzyNA3C820" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2011/02/early-look-at-jquery-ui-grid-in-aspnet.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-BrMz0ofs7QA/TVk9-QcdhMI/AAAAAAAAAIU/bzX0HBbtpN8/s72-c/jQueryUIGrid.jpg" height="72" width="72" /><thr:total>14</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-5177779216689311883</guid><pubDate>Wed, 15 Sep 2010 22:04:00 +0000</pubDate><atom:updated>2010-09-16T00:04:32.751+02:00</atom:updated><title>Speaking at MTS 2010 on "Rich user interface in ASP.NET MVC applications with jQuery plugins"</title><description>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_c2mfEqrjR68/TJFArc_TXcI/AAAAAAAAAHA/RBohGxCiDaY/s1600/mts2010_wlepka-180x200-OPrel.png" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" qx="true" src="http://4.bp.blogspot.com/_c2mfEqrjR68/TJFArc_TXcI/AAAAAAAAAHA/RBohGxCiDaY/s320/mts2010_wlepka-180x200-OPrel.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;In few weeks (October 5th and 6th) I will be attending the &lt;a href="http://www.mtskonferencja.pl/strona-glowna"&gt;MTS 2010 conference&lt;/a&gt; by Microsoft. On first day (October 5th) I will be speaking on "Rich user interface in ASP.NET MVC applications with jQuery plugins". There will be a little bit of talking and a lot of samples. I'm planning to cover CascadingDropDown, jTemplates, jQuery Treeview, jqGrid and few more.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;
&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;I will do my best to share the presentation here (video if possible) but it will be all in polish (as it is polish conference).&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=YSy7e_-tU-Y:uQfK7xL2OvY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=YSy7e_-tU-Y:uQfK7xL2OvY:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/YSy7e_-tU-Y" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/09/speaking-at-mts-2010-on-rich-user.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_c2mfEqrjR68/TJFArc_TXcI/AAAAAAAAAHA/RBohGxCiDaY/s72-c/mts2010_wlepka-180x200-OPrel.png" height="72" width="72" /><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-826853765994814809</guid><pubDate>Tue, 07 Sep 2010 22:02:00 +0000</pubDate><atom:updated>2011-04-01T16:21:09.549+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">asp.net</category><category domain="http://www.blogger.com/atom/ns#">cross-origin resource sharing</category><category domain="http://www.blogger.com/atom/ns#">cors</category><title>HttpHandler with cross-origin resource sharing support</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Recently I was playing around with &lt;em&gt;Cross-Origin Resource Sharing&lt;/em&gt; (you can read a W3C Working Draft for it &lt;a href="http://www.w3.org/TR/cors/"&gt;here&lt;/a&gt;), which is a mechanism to enable client-side cross-origin requests. As you can see, the last working draft is from 27 July 2010, so the technology is still in development. Let's take a look, how we can use it from JavaScript:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;...&lt;br /&gt;try {&lt;br /&gt;  //Create XMLHttpRequest and assign it to 'request' variable&lt;br /&gt;  ...&lt;br /&gt;&lt;br /&gt;  if (request) {&lt;br /&gt;    //Our request URL&lt;br /&gt;    var jsonUrl = 'http://localhost:60000/CrossOrigin';&lt;br /&gt;    //Check if XMLHttpRequest support CORS&lt;br /&gt;    if (request.withCredentials !== 'undefined') {&lt;br /&gt;      //If it does, prepare request&lt;br /&gt;      request.open('GET', jsonUrl, true);&lt;br /&gt;      request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');&lt;br /&gt;      request.onreadystatechange = function () {&lt;br /&gt;        if (request.readyState == 4) {&lt;br /&gt;          if (request.status == 200) {&lt;br /&gt;            document.getElementById('divTarget').innerHTML = request.responseText;&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      };&lt;br /&gt;    //If not, than check if XDomainRequest is available&lt;br /&gt;    } else if (typeof XDomainRequest != 'undefined') {&lt;br /&gt;      //If it is, prepare request&lt;br /&gt;      request = new XDomainRequest();&lt;br /&gt;      request.open('GET', jsonUrl);&lt;br /&gt;      request.onload = function () {&lt;br /&gt;        document.getElementById('divTarget').innerHTML = request.responseText;&lt;br /&gt;      };&lt;br /&gt;    } else {&lt;br /&gt;      throw (null);&lt;br /&gt;    }&lt;br /&gt;  } else {&lt;br /&gt;    throw (null);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  //Send request&lt;br /&gt;  request.send(null);&lt;br /&gt;} catch (e) {&lt;br /&gt;  //There is no support for CORS, use something else instead (for example JSONP)&lt;br /&gt;  ...&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The first condition checks for native support of &lt;em&gt;CORS&lt;/em&gt; through &lt;em&gt;XMLHttpRequest&lt;/em&gt;. This is the way to go for FireFox, Chrome and Safari - you don't need to write any special code, just standard &lt;em&gt;XMLHttpRequest&lt;/em&gt;. The second condition is for Internet Explorer, which supports cross-origin requests through &lt;em&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc288060(VS.85).aspx"&gt;XDomainRequest&lt;/a&gt;&lt;/em&gt;. I didn't managed to get it to work in Opera.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;So we know how to perform request, let's take a look underneath. What you see below, are requests from FireFox:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: plain;"&gt;OPTIONS&lt;br /&gt;Connection: keep-alive&lt;br /&gt;Keep-Alive: 115&lt;br /&gt;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&lt;br /&gt;Accept-Charset: ISO-8859-2,utf-8;q=0.7,*;q=0.7&lt;br /&gt;Accept-Encoding: gzip,deflate&lt;br /&gt;Accept-Language: pl,en-us;q=0.7,en;q=0.3&lt;br /&gt;Host: localhost:60000&lt;br /&gt;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729; .NET4.0E)&lt;br /&gt;Origin: http://localhost:50000&lt;br /&gt;Access-Control-Request-Method: GET&lt;br /&gt;Access-Control-Request-Headers: x-requested-with&lt;br /&gt;&lt;br /&gt;GET&lt;br /&gt;Connection: keep-alive&lt;br /&gt;Keep-Alive: 115&lt;br /&gt;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&lt;br /&gt;Accept-Charset: ISO-8859-2,utf-8;q=0.7,*;q=0.7&lt;br /&gt;Accept-Encoding: gzip,deflate&lt;br /&gt;Accept-Language: pl,en-us;q=0.7,en;q=0.3&lt;br /&gt;Host: localhost:60000&lt;br /&gt;Referer: http://localhost:50000/CORS.htm&lt;br /&gt;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729; .NET4.0E)&lt;br /&gt;X-Requested-With: XMLHttpRequest&lt;br /&gt;Origin: http://localhost:50000&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The first request (&lt;em&gt;OPTIONS&lt;/em&gt;) is a preflight request. Its job is to ensure that the resource is ok with the request. It uses following headers to perform check:&lt;ul&gt;&lt;li&gt;&lt;em&gt;Origin&lt;/em&gt; - It contains the origin of the request. You should put &lt;em&gt;Access-Control-Allow-Origin&lt;/em&gt; header with the same value into response if you accept the origin (you can also use '*' as a value if you consider your resource public).&lt;/li&gt;&lt;li&gt;&lt;em&gt;Access-Control-Request-Method&lt;/em&gt; - The method which will be used in actual request. In response you should put &lt;em&gt;Access-Control-Allow-Methods&lt;/em&gt; header with list of allowed methods separated by commas.&lt;/li&gt;&lt;li&gt;&lt;em&gt;Access-Control-Request-Headers&lt;/em&gt; - Comma separated list of custom headers which will be attached to request. You should put a list of headers which you accept into &lt;em&gt;Access-Control-Allow-Headers&lt;/em&gt; header in response.&lt;/li&gt;&lt;/ul&gt;The preflight request can be sometimes skipped when the methods are simple (for example IE does it with GET method). When the browser receives proper response, the actual request is being made. It differs from standard request by having &lt;em&gt;Origin&lt;/em&gt; header - you should put a proper &lt;em&gt;Access-Control-Allow-Origin&lt;/em&gt; into response. Unfortunately Chrome and Safari doesn't put &lt;em&gt;Origin&lt;/em&gt; into request, but they still require &lt;em&gt;Access-Control-Allow-Origin&lt;/em&gt; in response. That makes using '*&amp;quot; necessary if you want those browser to work.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;We now have enough knowledge to start writing our &lt;em&gt;HttpHandler&lt;/em&gt;:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;public class CrossOriginHandler : IHttpHandler&lt;br /&gt;{&lt;br /&gt;  #region IHttpHandler Members&lt;br /&gt;  public bool IsReusable&lt;br /&gt;  {&lt;br /&gt;    get { return true; }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void ProcessRequest(HttpContext context)&lt;br /&gt;  {&lt;br /&gt;    //Clear the response (just in case)&lt;br /&gt;    ClearResponse(context);&lt;br /&gt;&lt;br /&gt;    //Checking the method&lt;br /&gt;    switch (context.Request.HttpMethod.ToUpper())&lt;br /&gt;    {&lt;br /&gt;      //Cross-Origin preflight request&lt;br /&gt;      case &amp;quot;OPTIONS&amp;quot;:&lt;br /&gt;        //Set allowed method and headers&lt;br /&gt;        SetAllowCrossSiteRequestHeaders(context);&lt;br /&gt;        //Set allowed origin&lt;br /&gt;        SetAllowCrossSiteRequestOrigin(context);&lt;br /&gt;        break;&lt;br /&gt;      //Cross-Origin actual or simple request&lt;br /&gt;      case &amp;quot;GET&amp;quot;:&lt;br /&gt;        //Disable caching&lt;br /&gt;        SetNoCacheHeaders(context);&lt;br /&gt;        //Set allowed origin&lt;br /&gt;        SetAllowCrossSiteRequestOrigin(context);&lt;br /&gt;        //Generate response&lt;br /&gt;        context.Response.ContentType = &amp;quot;text/plain&amp;quot;;&lt;br /&gt;        context.Response.ContentEncoding = Encoding.UTF8;&lt;br /&gt;        context.Response.Write(&amp;quot;&amp;lt;h1&amp;gt;Hello World! [powered by Cross-Origin Resource Sharing]&amp;lt;/h1&amp;gt;&amp;quot;);&lt;br /&gt;        break;&lt;br /&gt;      //We doesn't support any other methods than OPTIONS and GET&lt;br /&gt;      default:&lt;br /&gt;        context.Response.Headers.Add(&amp;quot;Allow&amp;quot;, &amp;quot;OPTIONS, GET&amp;quot;);&lt;br /&gt;        context.Response.StatusCode = 405;&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    context.ApplicationInstance.CompleteRequest();&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  #region Methods&lt;br /&gt;  protected void ClearResponse(HttpContext context)&lt;br /&gt;  {&lt;br /&gt;    context.Response.ClearHeaders();&lt;br /&gt;    context.Response.ClearContent();&lt;br /&gt;    context.Response.Clear();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  protected void SetNoCacheHeaders(HttpContext context)&lt;br /&gt;  {&lt;br /&gt;    context.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));&lt;br /&gt;    context.Response.Cache.SetValidUntilExpires(false);&lt;br /&gt;    context.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);&lt;br /&gt;    context.Response.Cache.SetCacheability(HttpCacheability.NoCache);&lt;br /&gt;    context.Response.Cache.SetNoStore();&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This code should be easy to understand, but there are two key methods missing. Let's start with the one which puts &lt;em&gt;Access-Control-Allow-Methods&lt;/em&gt; and &lt;em&gt;Access-Control-Allow-Headers&lt;/em&gt; headers into response:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;private void SetAllowCrossSiteRequestHeaders(HttpContext context)&lt;br /&gt;{&lt;br /&gt;  //We allow only GET method&lt;br /&gt;  string requestMethod = context.Request.Headers[&amp;quot;Access-Control-Request-Method&amp;quot;];&lt;br /&gt;  if (!String.IsNullOrEmpty(requestMethod) &amp;amp;&amp;amp; requestMethod.ToUpper() == &amp;quot;GET&amp;quot;)&lt;br /&gt;    context.Response.AppendHeader(&amp;quot;Access-Control-Allow-Methods&amp;quot;, &amp;quot;GET&amp;quot;);&lt;br /&gt;&lt;br /&gt;  //We allow any custom headers&lt;br /&gt;  string requestHeaders = context.Request.Headers[&amp;quot;Access-Control-Request-Headers&amp;quot;];&lt;br /&gt;  if (!String.IsNullOrEmpty(requestHeaders))&lt;br /&gt;    context.Response.AppendHeader(&amp;quot;Access-Control-Allow-Headers&amp;quot;, requestHeaders);&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now let's add the one which deals with &lt;em&gt;Origin&lt;/em&gt;:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;private void SetAllowCrossSiteRequestOrigin(HttpContext context)&lt;br /&gt;{&lt;br /&gt;  string origin = context.Request.Headers[&amp;quot;Origin&amp;quot;];&lt;br /&gt;  if (!String.IsNullOrEmpty(origin))&lt;br /&gt;    //You can make some sophisticated checks here&lt;br /&gt;    context.Response.AppendHeader(&amp;quot;Access-Control-Allow-Origin&amp;quot;, origin);&lt;br /&gt;  else&lt;br /&gt;    //This is necessary for Chrome/Safari actual request&lt;br /&gt;    context.Response.AppendHeader(&amp;quot;Access-Control-Allow-Origin&amp;quot;, &amp;quot;*&amp;quot;);&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;As you can see, the method takes the absence of &lt;em&gt;Origin&lt;/em&gt; header in Chrome and Safari into consideration.&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Complete sample application can be found &lt;a href="http://tpeczek.codeplex.com/releases/view/51988"&gt;here&lt;/a&gt;, go ahead and make some use of it.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=Z6lfuTupdCY:6ThtSOsaVE4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=Z6lfuTupdCY:6ThtSOsaVE4:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/Z6lfuTupdCY" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/09/httphandler-with-cross-origin-resource.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><thr:total>15</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-1880279190636967311</guid><pubDate>Tue, 31 Aug 2010 22:36:00 +0000</pubDate><atom:updated>2010-09-01T00:38:02.466+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">client ip</category><category domain="http://www.blogger.com/atom/ns#">asp.net</category><category domain="http://www.blogger.com/atom/ns#">http headers</category><title>Attempting to retrieve a user's real IP address</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Lately, I was in need of retrieving user's IP address. The first place I went looking was &lt;em&gt;REMOTE_ADDR&lt;/em&gt; server variable. Unfortunately, due to all proxy servers out there, this variable can be pretty far from user's real IP address. After some googling I have put together a list of HTTP headers that might contain the real IP address:     &lt;ul&gt;     &lt;li&gt;CLIENT-IP &lt;/li&gt;      &lt;li&gt;X-FORWARDED-FOR &lt;/li&gt;      &lt;li&gt;X-FORWARDED &lt;/li&gt;      &lt;li&gt;X-CLUSTER-CLIENT-IP &lt;/li&gt;      &lt;li&gt;FORWARDED-FOR &lt;/li&gt;      &lt;li&gt;FORWARDED &lt;/li&gt;   &lt;/ul&gt; It's important to know, that &lt;em&gt;X-FORWARDED-FOR&lt;/em&gt; may contain a comma+space separated list of IP addresses.&lt;/span&gt; &lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Having that list in mind, we can write a simple method which will attempt to retrieve user's real IP address:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;   &lt;pre class="brush: csharp;"&gt;public string DetermineIP(HttpContext context)&lt;br /&gt;{&lt;br /&gt;  if (context.Request.ServerVariables.AllKeys.Contains(&amp;quot;HTTP_CLIENT_IP&amp;quot;) &amp;amp;&amp;amp; CheckIP(context.Request.ServerVariables[&amp;quot;HTTP_CLIENT_IP&amp;quot;]))&lt;br /&gt;    return context.Request.ServerVariables[&amp;quot;HTTP_CLIENT_IP&amp;quot;];&lt;br /&gt;&lt;br /&gt;  if (context.Request.ServerVariables.AllKeys.Contains(&amp;quot;HTTP_X_FORWARDED_FOR&amp;quot;))&lt;br /&gt;    foreach (string ip in context.Request.ServerVariables[&amp;quot;HTTP_X_FORWARDED_FOR&amp;quot;].Split(','))&lt;br /&gt;      if (CheckIP(ip.Trim()))&lt;br /&gt;        return ip.Trim();&lt;br /&gt;&lt;br /&gt;  if (context.Request.ServerVariables.AllKeys.Contains(&amp;quot;HTTP_X_FORWARDED&amp;quot;) &amp;amp;&amp;amp; CheckIP(context.Request.ServerVariables[&amp;quot;HTTP_X_FORWARDED&amp;quot;]))&lt;br /&gt;    return context.Request.ServerVariables[&amp;quot;HTTP_X_FORWARDED&amp;quot;];&lt;br /&gt;&lt;br /&gt;  if (context.Request.ServerVariables.AllKeys.Contains(&amp;quot;HTTP_X_CLUSTER_CLIENT_IP&amp;quot;) &amp;amp;&amp;amp; CheckIP(context.Request.ServerVariables[&amp;quot;HTTP_X_CLUSTER_CLIENT_IP&amp;quot;]))&lt;br /&gt;    return context.Request.ServerVariables[&amp;quot;HTTP_X_CLUSTER_CLIENT_IP&amp;quot;];&lt;br /&gt;&lt;br /&gt;  if (context.Request.ServerVariables.AllKeys.Contains(&amp;quot;HTTP_FORWARDED_FOR&amp;quot;) &amp;amp;&amp;amp; CheckIP(context.Request.ServerVariables[&amp;quot;HTTP_FORWARDED_FOR&amp;quot;]))&lt;br /&gt;    return context.Request.ServerVariables[&amp;quot;HTTP_FORWARDED_FOR&amp;quot;];&lt;br /&gt;&lt;br /&gt;  if (context.Request.ServerVariables.AllKeys.Contains(&amp;quot;HTTP_FORWARDED&amp;quot;) &amp;amp;&amp;amp; CheckIP(context.Request.ServerVariables[&amp;quot;HTTP_FORWARDED&amp;quot;]))&lt;br /&gt;    return context.Request.ServerVariables[&amp;quot;HTTP_FORWARDED&amp;quot;];&lt;br /&gt;&lt;br /&gt;  return context.Request.ServerVariables[&amp;quot;REMOTE_ADDR&amp;quot;];&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;So how about this &lt;em&gt;CheckIP&lt;/em&gt; method? The purpose of this method is to ensure that IP address is both a valid IP and does not fall within a private network range:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;br /&gt;  &lt;pre class="brush: csharp;"&gt;private bool CheckIP(string ip)&lt;br /&gt;{&lt;br /&gt;  if (!String.IsNullOrEmpty(ip))&lt;br /&gt;  {&lt;br /&gt;    long ipToLong = -1;&lt;br /&gt;    //Is it valid IP address&lt;br /&gt;    if (TryConvertIPToLong(ip, out ipToLong))&lt;br /&gt;    {&lt;br /&gt;      //Does it fall within a private network range&lt;br /&gt;      foreach (long[] privateIp in _privateIps)&lt;br /&gt;        if ((ipToLong &amp;gt;= privateIp[0]) &amp;amp;&amp;amp; (ipToLong &amp;lt;= privateIp[1]))&lt;br /&gt;          return false;&lt;br /&gt;        return true;&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;      return false;&lt;br /&gt;  }&lt;br /&gt;  else&lt;br /&gt;    return false;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we are missing only two things. The first one is a method which converts IP from &lt;em&gt;string&lt;/em&gt; to &lt;em&gt;long&lt;/em&gt;:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;br /&gt;  &lt;pre class="brush: csharp;"&gt;private long ConvertIPToLong(string ip)&lt;br /&gt;{&lt;br /&gt;  string[] ipSplit = ip.Split('.');&lt;br /&gt;  return (16777216 * Convert.ToInt32(ipSplit[0]) + 65536 * Convert.ToInt32(ipSplit[1]) + 256 * Convert.ToInt32(ipSplit[2]) + Convert.ToInt32(ipSplit[3])); &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private bool TryConvertIPToLong(string ip, out long ipToLong)&lt;br /&gt;{&lt;br /&gt;  try&lt;br /&gt;  {&lt;br /&gt;    ipToLong = ConvertIPToLong(ip);&lt;br /&gt;    return true;&lt;br /&gt;  }&lt;br /&gt;  catch&lt;br /&gt;  {&lt;br /&gt;    ipToLong = -1;&lt;br /&gt;    return false;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The second thing is an array of private network IP ranges:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;br /&gt;  &lt;pre class="brush: csharp;"&gt;private long[][] _privateIps = new long[][] {&lt;br /&gt;  new long[] {ConvertIPToLong(&amp;quot;0.0.0.0&amp;quot;), ConvertIPToLong(&amp;quot;2.255.255.255&amp;quot;)},&lt;br /&gt;  new long[] {ConvertIPToLong(&amp;quot;10.0.0.0&amp;quot;), ConvertIPToLong(&amp;quot;10.255.255.255&amp;quot;)},&lt;br /&gt;  new long[] {ConvertIPToLong(&amp;quot;127.0.0.0&amp;quot;), ConvertIPToLong(&amp;quot;127.255.255.255&amp;quot;)},&lt;br /&gt;  new long[] {ConvertIPToLong(&amp;quot;169.254.0.0&amp;quot;), ConvertIPToLong(&amp;quot;169.254.255.255&amp;quot;)},&lt;br /&gt;  new long[] {ConvertIPToLong(&amp;quot;172.16.0.0&amp;quot;), ConvertIPToLong(&amp;quot;172.31.255.255&amp;quot;)},&lt;br /&gt;  new long[] {ConvertIPToLong(&amp;quot;192.0.2.0&amp;quot;), ConvertIPToLong(&amp;quot;192.0.2.255&amp;quot;)},&lt;br /&gt;  new long[] {ConvertIPToLong(&amp;quot;192.168.0.0&amp;quot;), ConvertIPToLong(&amp;quot;192.168.255.255&amp;quot;)},&lt;br /&gt;  new long[] {ConvertIPToLong(&amp;quot;255.255.255.0&amp;quot;), ConvertIPToLong(&amp;quot;255.255.255.255&amp;quot;)}&lt;br /&gt;};&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we are good to go. Please keep in mind, that this approach doesn't guarantee that you will retrieve real IP address, as all of those headers are optional.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=VcW9O-MB27M:53zxVBlqnTE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=VcW9O-MB27M:53zxVBlqnTE:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/VcW9O-MB27M" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/09/attempting-to-retrieve-user-real-ip.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-8010751001051162900</guid><pubDate>Thu, 15 Jul 2010 22:46:00 +0000</pubDate><atom:updated>2011-03-31T14:20:32.513+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">asp.net</category><category domain="http://www.blogger.com/atom/ns#">ajax</category><category domain="http://www.blogger.com/atom/ns#">jquery ui progressbar</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><title>Reporting server side operation progress with jQuery UI Progressbar</title><description>&lt;span style="text-align: justify; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;A colleague of mine recently had a problem with using &lt;a href="http://jqueryui.com/demos/progressbar/"&gt;jQuery UI Progressbar&lt;/a&gt; for reporting progress of asynchronous server side operations initialized via AJAX request. I decided to create a short sample for him and everybody else who might need it. I'm going to show how to do it in ASP.NET MVC and ASP.NET WebForms.&lt;/span&gt;&lt;br /&gt;&lt;span style="text-align: justify; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;We will start with ASP.NET MVC sample. First thing to do is adding some JavaScript and CSS references:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;link href=&amp;quot;&amp;lt;%= Url.Content(&amp;quot;~/Content/jquery-ui-1.8.2.css&amp;quot;) %&amp;gt;&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;&amp;lt;%= Url.Content(&amp;quot;~/Scripts/jquery-1.4.2.min.js&amp;quot;) %&amp;gt;&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;&amp;lt;%= Url.Content(&amp;quot;~/Scripts/jquery-ui-1.8.2.min.js&amp;quot;) %&amp;gt;&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="text-align: justify; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Markup for &lt;em&gt;Progressbar&lt;/em&gt; is very simple (just one div), so we will need only two lines of &lt;em&gt;HTML&lt;/em&gt; in this sample:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;button id=&amp;quot;operation&amp;quot;&amp;gt;Operation&amp;lt;/button&amp;gt;&lt;br /&gt;&amp;lt;div id=&amp;quot;progressbar&amp;quot; style=&amp;quot;width:500px&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="text-align: justify; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now some interesting stuff begins. We need two controller actions. One for triggering actual process and one for reporting progress:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Action for triggering long running operation&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br /&gt;[AcceptVerbs(HttpVerbs.Post)]&lt;br /&gt;public ActionResult Operation()&lt;br /&gt;{&lt;br /&gt;  HttpSessionStateBase session = Session;&lt;br /&gt;&lt;br /&gt;  //Separate thread for long running operation&lt;br /&gt;  ThreadPool.QueueUserWorkItem(delegate&lt;br /&gt;  {&lt;br /&gt;    int operationProgress;&lt;br /&gt;    for (operationProgress = 0; operationProgress &amp;lt;= 100; operationProgress = operationProgress + 2)&lt;br /&gt;    {&lt;br /&gt;      session[&amp;quot;OPERATION_PROGRESS&amp;quot;] = operationProgress;&lt;br /&gt;      Thread.Sleep(1000);&lt;br /&gt;    }&lt;br /&gt;  });&lt;br /&gt;&lt;br /&gt;  return Json(new { progress = 0 });&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// Action for reporting operation progress&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br /&gt;[NoCache]&lt;br /&gt;public ActionResult OperationProgress()&lt;br /&gt;{&lt;br /&gt;  int operationProgress = 0;&lt;br /&gt;&lt;br /&gt;  if (Session[&amp;quot;OPERATION_PROGRESS&amp;quot;] != null)&lt;br /&gt;    operationProgress = (int)Session[&amp;quot;OPERATION_PROGRESS&amp;quot;];&lt;br /&gt;&lt;br /&gt;  return Json(new { progress = operationProgress }, JsonRequestBehavior.AllowGet);&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="text-align: justify; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;What is missing is JavaScript, which will initialize &lt;em&gt;Progressbar&lt;/em&gt;, trigger the operation and set timer for updating progress:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;  $(document).ready(function () {&lt;br /&gt;    //Progressbar initialization&lt;br /&gt;    $(&amp;quot;#progressbar&amp;quot;).progressbar({ value: 0 });&lt;br /&gt;    //Button click event&lt;br /&gt;    $(&amp;quot;#operation&amp;quot;).click(function (e) {&lt;br /&gt;      //Disabling button&lt;br /&gt;      $(&amp;quot;#operation&amp;quot;).attr('disabled', 'disabled');&lt;br /&gt;      //Making sure that progress indicate 0&lt;br /&gt;      $(&amp;quot;#progressbar&amp;quot;).progressbar('value', 0);&lt;br /&gt;      //Perform POST for triggering long running operation&lt;br /&gt;      $.post('&amp;lt;%: Url.Action(&amp;quot;Operation&amp;quot;) %&amp;gt;', function (data) {&lt;br /&gt;        //Updating progress&lt;br /&gt;        $(&amp;quot;#progressbar&amp;quot;).progressbar('value', data.progress);&lt;br /&gt;        //Setting the timer&lt;br /&gt;        window.progressIntervalId = window.setInterval(function () {&lt;br /&gt;          //Getting current operation progress&lt;br /&gt;          $.get('&amp;lt;%: Url.Action(&amp;quot;OperationProgress&amp;quot;) %&amp;gt;', function (data) {&lt;br /&gt;            //Updating progress&lt;br /&gt;            $(&amp;quot;#progressbar&amp;quot;).progressbar('value', data.progress);&lt;br /&gt;            //If operation is complete&lt;br /&gt;            if (data.progress == 100) {&lt;br /&gt;              //Clear timer&lt;br /&gt;              window.clearInterval(window.progressIntervalId);&lt;br /&gt;              //Enable button&lt;br /&gt;              $(&amp;quot;#operation&amp;quot;).attr('disabled', '');&lt;br /&gt;            }&lt;br /&gt;          });&lt;br /&gt;        }, 500);&lt;br /&gt;      });&lt;br /&gt;    });&lt;br /&gt;  });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="text-align: justify; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The result looks like this:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://2.bp.blogspot.com/_c2mfEqrjR68/TD-IcptOIKI/AAAAAAAAAGc/LWXP9HSGIkQ/s1600/progressbarmvc.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_c2mfEqrjR68/TD-IcptOIKI/AAAAAAAAAGc/LWXP9HSGIkQ/s320/progressbarmvc.jpg" rw="true" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="text-align: justify; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;To make it work in ASP.NET WebForms, we need two PageMethods instead of actions:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// PageMethod for triggering long running operation&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br /&gt;[System.Web.Services.WebMethod(EnableSession=true)]&lt;br /&gt;public static object Operation()&lt;br /&gt;{&lt;br /&gt;  HttpSessionState session = HttpContext.Current.Session;&lt;br /&gt;&lt;br /&gt;  //Separate thread for long running operation&lt;br /&gt;  ThreadPool.QueueUserWorkItem(delegate&lt;br /&gt;  {&lt;br /&gt;    int operationProgress;&lt;br /&gt;    for (operationProgress = 0; operationProgress &amp;lt;= 100; operationProgress = operationProgress + 2)&lt;br /&gt;    {&lt;br /&gt;      session[&amp;quot;OPERATION_PROGRESS&amp;quot;] = operationProgress;&lt;br /&gt;      Thread.Sleep(1000);&lt;br /&gt;    }&lt;br /&gt;  });&lt;br /&gt;&lt;br /&gt;  return new { progress = 0 };&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// PageMethod for reporting progress&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br /&gt;[System.Web.Services.WebMethod(EnableSession = true)]&lt;br /&gt;public static object OperationProgress()&lt;br /&gt;{&lt;br /&gt;  int operationProgress = 0;&lt;br /&gt;&lt;br /&gt;  if (HttpContext.Current.Session[&amp;quot;OPERATION_PROGRESS&amp;quot;] != null)&lt;br /&gt;    operationProgress = (int)HttpContext.Current.Session[&amp;quot;OPERATION_PROGRESS&amp;quot;];&lt;br /&gt;&lt;br /&gt;  return new { progress = operationProgress };&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="text-align: justify; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;and modified JavaScript:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;  $(document).ready(function () {&lt;br /&gt;    //Progressbar initialization&lt;br /&gt;    $(&amp;quot;#progressbar&amp;quot;).progressbar({ value: 0 });&lt;br /&gt;    //Button click event&lt;br /&gt;    $(&amp;quot;#operation&amp;quot;).click(function (e) {&lt;br /&gt;      //Disabling button&lt;br /&gt;      $(&amp;quot;#operation&amp;quot;).attr('disabled', 'disabled');&lt;br /&gt;      //Making sure that progress indicate 0&lt;br /&gt;      $(&amp;quot;#progressbar&amp;quot;).progressbar('value', 0);&lt;br /&gt;      //Call PageMethod which triggers long running operation&lt;br /&gt;      PageMethods.Operation(function(result) {&lt;br /&gt;        if (result) {&lt;br /&gt;          //Updating progress&lt;br /&gt;          $(&amp;quot;#progressbar&amp;quot;).progressbar('value', result.progress)&lt;br /&gt;          //Setting the timer&lt;br /&gt;          window.progressIntervalId = window.setInterval(function () {&lt;br /&gt;            //Calling PageMethod for current progress&lt;br /&gt;            PageMethods.OperationProgress(function (result) {&lt;br /&gt;              //Updating progress&lt;br /&gt;              $(&amp;quot;#progressbar&amp;quot;).progressbar('value', result.progress)&lt;br /&gt;              //If operation is complete&lt;br /&gt;              if (result.progress == 100) {&lt;br /&gt;                //Clear timer&lt;br /&gt;                window.clearInterval(window.progressIntervalId);&lt;br /&gt;                //Enable button&lt;br /&gt;                $(&amp;quot;#operation&amp;quot;).attr('disabled', '');&lt;br /&gt;              }&lt;br /&gt;            });&lt;br /&gt;          }, 500);&lt;br /&gt;        }&lt;br /&gt;      });&lt;br /&gt;    });&lt;br /&gt;  });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="text-align: justify; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The effect is pretty much the same:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://2.bp.blogspot.com/_c2mfEqrjR68/TD-Mpg42HHI/AAAAAAAAAGk/sxQQj2lv8RQ/s1600/progressbarforms.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_c2mfEqrjR68/TD-Mpg42HHI/AAAAAAAAAGk/sxQQj2lv8RQ/s320/progressbarforms.jpg" rw="true" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="text-align: justify; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The samples for ASP.NET MVC and ASP.NET WebForms can be downloaded &lt;a href="http://tpeczek.codeplex.com/releases/view/52932"&gt;here&lt;/a&gt;. Enjoy.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=mF2NciZkk6g:WG3t6IFWsk4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=mF2NciZkk6g:WG3t6IFWsk4:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/mF2NciZkk6g" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/07/reporting-server-side-operation.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_c2mfEqrjR68/TD-IcptOIKI/AAAAAAAAAGc/LWXP9HSGIkQ/s72-c/progressbarmvc.jpg" height="72" width="72" /><thr:total>18</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-2978826830959769828</guid><pubDate>Fri, 25 Jun 2010 18:01:00 +0000</pubDate><atom:updated>2011-03-31T10:34:04.819+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">jquery</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><category domain="http://www.blogger.com/atom/ns#">jeditable</category><title>Glance at jEditable in ASP.NET MVC</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Recently one of my colleagues suggested that I should take a look at &lt;a href="http://www.appelsiini.net/projects/jeditable"&gt;Jeditable plugin&lt;/a&gt;. This plugin allows in place edition of XHTML elements content. I can imagine few interesting scenarios with this plugin, so I decide to put together a simple sample.&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Let's start with some markup, which will represent an &lt;em&gt;NorthWind&lt;/em&gt; employee details (you can download &lt;em&gt;NorthWind&lt;/em&gt; database from &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=06616212-0356-46a0-8da2-eebc53a68034&amp;amp;displaylang=en"&gt;here&lt;/a&gt;):&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;TitleOfCourtesy: &amp;lt;u&amp;gt;&amp;lt;%: Model.TitleOfCourtesy %&amp;gt;&amp;lt;/u&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;FirstName: &amp;lt;u&amp;gt;&amp;lt;%: Model.FirstName %&amp;gt;&amp;lt;/u&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;LastName: &amp;lt;u&amp;gt;&amp;lt;%: Model.LastName %&amp;gt;&amp;lt;/u&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;Title: &amp;lt;b class=&amp;quot;edit&amp;quot; id=&amp;quot;Title&amp;quot;&amp;gt;&amp;lt;%: Model.Title %&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;Address: &amp;lt;b class=&amp;quot;edit&amp;quot; id=&amp;quot;Address&amp;quot;&amp;gt;&amp;lt;%: Model.Address %&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;PostalCode: &amp;lt;b class=&amp;quot;edit&amp;quot; id=&amp;quot;PostalCode&amp;quot;&amp;gt;&amp;lt;%: Model.PostalCode %&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;City: &amp;lt;b class=&amp;quot;edit&amp;quot; id=&amp;quot;City&amp;quot;&amp;gt;&amp;lt;%: Model.City %&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;Country: &amp;lt;b class=&amp;quot;edit-select&amp;quot; id=&amp;quot;Country&amp;quot;&amp;gt;&amp;lt;%: Model.Country %&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;Notes: &amp;lt;i class=&amp;quot;edit-area&amp;quot; id=&amp;quot;Notes&amp;quot;&amp;gt;&amp;lt;%: Model.Notes %&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;button id=&amp;quot;Submit&amp;quot;&amp;gt;Submit&amp;lt;/button&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;I would like to keep this sample a simple as possible, so there will be no fancy design or architecture:&lt;ul&gt;&lt;li&gt;fields which will be edited in standard &lt;em&gt;text&lt;/em&gt; input are wrapped in &amp;lt;b&amp;gt; element with class 'edit'&lt;/li&gt;&lt;li&gt;fields which will be edited in &lt;em&gt;select&lt;/em&gt; are wrapped in &amp;lt;b&amp;gt; element with class 'edit-select'&lt;/li&gt;&lt;li&gt;fields which will be edited in &lt;em&gt;textarea&lt;/em&gt; are wrapped in &amp;lt;i&amp;gt; element with class 'edit-area'&lt;/li&gt;&lt;/ul&gt;After making that clear, we can add &lt;em&gt;Jeditable&lt;/em&gt; functionality to those elements. First we should reference two scripts:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;script src=&amp;quot;&amp;lt;%= Url.Content(&amp;quot;~/Scripts/jquery-1.4.1.min.js&amp;quot;) %&amp;gt;&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;&amp;lt;%= Url.Content(&amp;quot;~/Scripts/jquery.jeditable.mini.js&amp;quot;) %&amp;gt;&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we can write some JavaScript:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;$(document).ready(function () {&lt;br /&gt;  //Standard 'text' inputs&lt;br /&gt;  $('.edit').editable($.updateEmployee, {&lt;br /&gt;    //Element tooltip&lt;br /&gt;    tooltip: 'Click to edit...',&lt;br /&gt;    //Input style&lt;br /&gt;    style: 'display: inline'&lt;br /&gt;  });&lt;br /&gt;  //Selects&lt;br /&gt;  $('.edit-select').editable($.updateEmployee, {&lt;br /&gt;    //Options for select (you can use loadurl if you want to request data from server)&lt;br /&gt;    data: &amp;quot;{'USA':'USA','UK':'UK'}&amp;quot;,&lt;br /&gt;    //Type&lt;br /&gt;    type: 'select',&lt;br /&gt;    //Text for accept button&lt;br /&gt;    submit: 'Accept',&lt;br /&gt;    //Element tooltip&lt;br /&gt;    tooltip: 'Click to edit...',&lt;br /&gt;    //Select style&lt;br /&gt;    style: 'display: inline'&lt;br /&gt;  });&lt;br /&gt;  //TextAreas&lt;br /&gt;  $('.edit-area').editable($.updateEmployee, {&lt;br /&gt;    //Type&lt;br /&gt;    type: 'textarea',&lt;br /&gt;    //Text for cancel button&lt;br /&gt;    cancel: 'Cancel',&lt;br /&gt;    //Text for accept button&lt;br /&gt;    submit: 'Accept',&lt;br /&gt;    //Element tooltip&lt;br /&gt;    tooltip: 'Click to edit...',&lt;br /&gt;    //TextArea style&lt;br /&gt;    style: 'display: inline'&lt;br /&gt;  });&lt;br /&gt;});&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The first parameter of &lt;em&gt;editable&lt;/em&gt; is usually an URL where browser posts edited content. In that situation, every field is being posted as soon as user finishes editing. There is also a possibility of passing function in first parameter. As you can see, I'm using second approach here. The &lt;em&gt;$.updateEmployee&lt;/em&gt; function looks like this:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;$.updateEmployee = function (value, settings) {&lt;br /&gt;  //Based on the current element, we update the corresponding property of employee&lt;br /&gt;  switch ($(this).attr('id')) {&lt;br /&gt;    case 'Title':&lt;br /&gt;      window.Employee.Title = value;&lt;br /&gt;      break;&lt;br /&gt;    case 'Address':&lt;br /&gt;      window.Employee.Address = value;&lt;br /&gt;      break;&lt;br /&gt;    case 'PostalCode':&lt;br /&gt;      window.Employee.PostalCode = value;&lt;br /&gt;      break;&lt;br /&gt;    case 'City':&lt;br /&gt;      window.Employee.City = value;&lt;br /&gt;      break;&lt;br /&gt;    case 'Country':&lt;br /&gt;      window.Employee.Country = value;&lt;br /&gt;      break;&lt;br /&gt;    case 'Notes':&lt;br /&gt;      window.Employee.Notes = value;&lt;br /&gt;      break;&lt;br /&gt;  }&lt;br /&gt;  //We have to return string, it will be put into element for displaying&lt;br /&gt;  return (value);&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;You may wonder where the &lt;em&gt;window.Employee&lt;/em&gt; object came from. It's being initialized like this (I know it's ugly, but it's only for sample purposes):&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;(function ($) {&lt;br /&gt;  window.Employee = {&lt;br /&gt;    EmployeeID: '&amp;lt;%: Model.EmployeeID %&amp;gt;',&lt;br /&gt;    Title: '&amp;lt;%: Model.Title %&amp;gt;',&lt;br /&gt;    Address: '&amp;lt;%: Model.Address %&amp;gt;',&lt;br /&gt;    PostalCode: '&amp;lt;%: Model.PostalCode %&amp;gt;',&lt;br /&gt;    City: '&amp;lt;%: Model.City %&amp;gt;',&lt;br /&gt;    Country: '&amp;lt;%: Model.Country %&amp;gt;',&lt;br /&gt;    Notes: '&amp;lt;%: Model.Notes %&amp;gt;'&lt;br /&gt;  };&lt;br /&gt;})(jQuery);&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This object allows me to perform a single &lt;em&gt;POST&lt;/em&gt; for all fields, when user clicks &lt;em&gt;Submit&lt;/em&gt; button:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;$('#Submit').click(function () {&lt;br /&gt;  $.ajax({&lt;br /&gt;    type: 'POST',&lt;br /&gt;    contentType: 'application/json; charset=utf-8',&lt;br /&gt;    url: '&amp;lt;%=Url.Action(&amp;quot;Details&amp;quot;, &amp;quot;Home&amp;quot;) %&amp;gt;',&lt;br /&gt;    dataType: 'json',&lt;br /&gt;    data: $.toJSON(window.Employee)&lt;br /&gt;  });&lt;br /&gt;});&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;You can go ahead and click around on our editable elements:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://1.bp.blogspot.com/_c2mfEqrjR68/TCToD78_8fI/AAAAAAAAAGE/ObWYQAY8Idc/s1600/jEditable.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_c2mfEqrjR68/TCToD78_8fI/AAAAAAAAAGE/ObWYQAY8Idc/s320/jEditable.jpg" ru="true" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Complete sample code can be downloaded &lt;a href="http://tpeczek.codeplex.com/releases/view/47835"&gt;here&lt;/a&gt;, enjoy.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=QK2jZh10hbY:hHI2LVTVtoY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=QK2jZh10hbY:hHI2LVTVtoY:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/QK2jZh10hbY" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/06/glance-at-jeditable-in-aspnet-mvc.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_c2mfEqrjR68/TCToD78_8fI/AAAAAAAAAGE/ObWYQAY8Idc/s72-c/jEditable.jpg" height="72" width="72" /><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-3368040823461105779</guid><pubDate>Wed, 16 Jun 2010 23:15:00 +0000</pubDate><atom:updated>2010-06-17T01:19:12.767+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">toolkitscriptmanager</category><category domain="http://www.blogger.com/atom/ns#">sys.services.authenticationservice</category><category domain="http://www.blogger.com/atom/ns#">asp.net</category><category domain="http://www.blogger.com/atom/ns#">ajaxcontroltoolkit</category><title>ASP.NET 3.5, ToolkitScriptManager 3.5.40412 and Sys.Services.AuthenticationService</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Today I have updated &lt;em&gt;AjaxControlToolkit&lt;/em&gt; in one of my ASP.NET 3.5 projects to version 3.5.40412 (there are few important bug fixes for me in this version). If someone would just replace the reference to &lt;em&gt;AjaxControlToolkit.dll &lt;/em&gt;(like I did) he would see following error message:&lt;/span&gt;   &lt;br /&gt;  &lt;br /&gt;  &lt;div style="text-align: center; font-style: italic; font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;AjaxControlToolkit requires ASP.NET Ajax 4.0 scripts. Ensure the correct version of the scripts are referenced. If you are using an ASP.NET ScriptManager, switch to the ToolkitScriptManager in AjaxControlToolkit.dll.&lt;/div&gt;  &lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The message is pretty clear, so I replaced &lt;em&gt;ScriptManager&lt;/em&gt; with &lt;em&gt;ToolkitScriptManager&lt;/em&gt;:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;   &lt;pre class="brush: xml;"&gt;&amp;lt;AjaxToolkit:ToolkitScriptManager ID=&amp;quot;smContent&amp;quot; EnablePageMethods=&amp;quot;true&amp;quot; EnableScriptGlobalization=&amp;quot;true&amp;quot; EnableScriptLocalization=&amp;quot;true&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;/AjaxToolkit:ToolkitScriptManager&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;After that change everything seemed to work just fine, until I decided to log in. It happens that this project is using &lt;em&gt;Sys.Services.AuthenticationService&lt;/em&gt; for login and logout operations. Any attempt to login resulted in &lt;em&gt;'object doesn't support this property or method'&lt;/em&gt; message. So something must be wrong with JavaScript's emitted by manager. I made a quick comparison of scripts referenced by &lt;em&gt;ScriptManager&lt;/em&gt; and &lt;em&gt;ToolkitScriptManager&lt;/em&gt;. Here are the headers of interesting one:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;// Name:        MicrosoftAjax.js&lt;br /&gt;// Assembly:    System.Web.Extensions&lt;br /&gt;// Version:     3.5.0.0&lt;br /&gt;// FileVersion: 3.5.30729.196&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;&lt;br /&gt;// Name:        MicrosoftAjax.js&lt;br /&gt;// Assembly:    AjaxControlToolkit&lt;br /&gt;// Version:     3.5.40412.0&lt;br /&gt;// FileVersion: 3.5.40412.2&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The &lt;em&gt;MicrosoftAjax.js&lt;/em&gt; referenced by &lt;em&gt;ToolkitScriptManager&lt;/em&gt; has a lot less content than the one referenced by &lt;em&gt;ScriptManager&lt;/em&gt;. Judging by the first error message, this script should be the one from &lt;em&gt;ASP.NET AJAX 4.0&lt;/em&gt; scripts. If that's the case, lets take a look at &lt;em&gt;Microsoft AJAX CDN&lt;/em&gt; for &lt;a href="http://www.asp.net/ajaxlibrary/CDNAjax35.ashx"&gt;ASP.NET AJAX 3.5&lt;/a&gt; and &lt;a href="http://www.asp.net/ajaxlibrary/CDNAjax4.ashx"&gt;ASP.NET AJAX 4.0&lt;/a&gt;. As you can see, in &lt;em&gt;ASP.NET AJAX 4.0&lt;/em&gt; Microsoft has split &lt;em&gt;MicrosoftAjax.js&lt;/em&gt; in a lot of smaller files. The one we need is &lt;em&gt;MicrosoftAjaxApplicationServices.js&lt;/em&gt;, let's download it and add to &lt;em&gt;ToolkitScriptManager&lt;/em&gt; scripts:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;br /&gt;  &lt;pre class="brush: xml;"&gt;&amp;lt;AjaxToolkit:ToolkitScriptManager ID=&amp;quot;smContent&amp;quot; EnablePageMethods=&amp;quot;true&amp;quot; EnableScriptGlobalization=&amp;quot;true&amp;quot; EnableScriptLocalization=&amp;quot;true&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;&lt;br /&gt;  &amp;lt;Scripts&amp;gt;&lt;br /&gt;    &amp;lt;asp:ScriptReference Path=&amp;quot;~/Scripts/MicrosoftAjaxApplicationServices.js&amp;quot; /&amp;gt;&lt;br /&gt;  &amp;lt;/Scripts&amp;gt;&lt;br /&gt;&amp;lt;/AjaxToolkit:ToolkitScriptManager&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Unfortunately this still doesn't work. The reason is that inline script, which sets default path for service, is executed before the script we have just added. We need to set the path for the service ourselves:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;br /&gt;  &lt;pre class="brush: js;"&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;  Sys.Application.add_init(function() { Sys.Services.AuthenticationService.set_path('&amp;lt;%= ResolveClientUrl(&amp;quot;~/Authentication_JSON_AppService.axd&amp;quot;) %&amp;gt;'); });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now it will work. I hope that this will be helpful for people who will encounter similar problem.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=bLFa0rl8hv4:I9C2MeiOFbM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=bLFa0rl8hv4:I9C2MeiOFbM:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/bLFa0rl8hv4" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/06/aspnet-35-toolkitscriptmanager-3540412.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-3786224702814909556</guid><pubDate>Mon, 07 Jun 2010 12:19:00 +0000</pubDate><atom:updated>2011-03-10T12:02:39.568+01:00</atom:updated><title>Partial forms validation in ASP.NET MVC 2 (something like WebForms ValidationGroup)</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;In one of my recent ASP.NET MVC 2 projects I had to make a form divided into few tabs. Each tab had to be validated before user can move to next one. Unfortunately ASP.NET MVC 2 built in validation doesn't provide mechanism for this. Well we are developers, so if there is no built in mechanism, we should create our own. First lets create a &lt;em&gt;ValidationAttribute&lt;/em&gt;, which will be used to add information about validation group:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;   &lt;pre class="brush: csharp;"&gt;[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class ValidationGroupAttribute : ValidationAttribute
{
  #region Properties
  /// &amp;lt;summary&amp;gt;
  /// Name of the validation group
  /// &amp;lt;/summary&amp;gt;
  public string GroupName { get; set; }
  #endregion

  #region Constructor
  public ValidationGroupAttribute(string groupName)
  {
    GroupName = groupName;
  }
  #endregion

  #region Methods
  public override bool IsValid(object value)
  {
    //No validation logic, always return true
    return true;
  }
  #endregion
}&lt;/pre&gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;We will also need a &lt;em&gt;DataAnnotationsModelValidator&lt;/em&gt; for this attribute:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;br /&gt;
&lt;pre class="brush: csharp;"&gt;public class ValidationGroupValidator : DataAnnotationsModelValidator&amp;lt;ValidationGroupAttribute&amp;gt;
{
  #region Fields
  string _groupName;
  #endregion

  #region Constructor
  public ValidationGroupValidator(ModelMetadata metadata, ControllerContext context, ValidationGroupAttribute attribute)
: base(metadata, context, attribute) 
  {
    _groupName = attribute.GroupName;
  }
  #endregion

  #region Methods
  public override IEnumerable&amp;lt;ModelClientValidationRule&amp;gt; GetClientValidationRules()
  {
    //Add informations about validation group to metadata
    var validatioRule = new ModelClientValidationRule
    {
      ErrorMessage = String.Empty,
      ValidationType = &amp;quot;validationGroup&amp;quot;
    };
    validatioRule.ValidationParameters.Add(&amp;quot;groupName&amp;quot;, _groupName);

    return new[] { validatioRule };
  }
  #endregion
}&lt;/pre&gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Don't forget to register above classes in your &lt;em&gt;Global.asax&lt;/em&gt;:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;br /&gt;
&lt;pre class="brush: csharp;"&gt;DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(ValidationGroupAttribute), typeof(ValidationGroupValidator));&lt;/pre&gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;So this is all we need on server side (please remember, that we don't want to achieve any server side logic, only partial validation on client side before posting the whole form). To make it work on client side, first we need to modify &lt;em&gt;Sys.Mvc.FormContext._parseJsonOptions&lt;/em&gt; in &lt;em&gt;MicrosoftMvcValidation.debug.js&lt;/em&gt; (or corresponding part in &lt;em&gt;MicrosoftMvcValidation.js&lt;/em&gt;):&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;br /&gt;
&lt;pre class="brush: js;"&gt;Sys.Mvc.FormContext._parseJsonOptions = function Sys_Mvc_FormContext$_parseJsonOptions(options) {
  var formElement = $get(options.FormId);
  var validationSummaryElement = (!Sys.Mvc._validationUtil.stringIsNullOrEmpty(options.ValidationSummaryId)) ? $get(options.ValidationSummaryId) : null;
  var formContext = new Sys.Mvc.FormContext(formElement, validationSummaryElement);
  formContext.enableDynamicValidation();
  formContext.replaceValidationSummary = options.ReplaceValidationSummary;
  for (var i = 0; i &amp;lt; options.Fields.length; i++) {
    var field = options.Fields[i];
    var fieldElements = Sys.Mvc.FormContext._getFormElementsWithName(formElement, field.FieldName);
    var validationMessageElement = (!Sys.Mvc._validationUtil.stringIsNullOrEmpty(field.ValidationMessageId)) ? $get(field.ValidationMessageId) : null;
    var fieldContext = new Sys.Mvc.FieldContext(formContext);
    Array.addRange(fieldContext.elements, fieldElements);
    fieldContext.validationMessageElement = validationMessageElement;
    fieldContext.replaceValidationMessageContents = field.ReplaceValidationMessageContents;
    for (var j = 0; j &amp;lt; field.ValidationRules.length; j++) {
      var rule = field.ValidationRules[j];
      //Here goes our small modification
      if (rule.ValidationType == 'validationGroup') {
        fieldContext.validationGroup = rule.ValidationParameters['groupName'];
      }
      else {
        var validator = Sys.Mvc.ValidatorRegistry.getValidator(rule);
        if (validator) {
          var validation = Sys.Mvc.$create_Validation();
          validation.fieldErrorMessage = rule.ErrorMessage;
          validation.validator = validator;
          Array.add(fieldContext.validations, validation);
        }
      }
    }
    fieldContext.enableDynamicValidation();
    Array.add(formContext.fields, fieldContext);
  }
  var registeredValidatorCallbacks = formElement.validationCallbacks;
  if (!registeredValidatorCallbacks) {
    registeredValidatorCallbacks = [];
    formElement.validationCallbacks = registeredValidatorCallbacks;
  }
  registeredValidatorCallbacks.push(Function.createDelegate(null, function () {
    return Sys.Mvc._validationUtil.arrayIsNullOrEmpty(formContext.validate('submit'));
  }));
  return formContext;
}&lt;/pre&gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we can write ourselves function, which will perform partial validation based on group name:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;br /&gt;
&lt;pre class="brush: js;"&gt;Sys.Mvc.FormContext.validateGroup = function Sys_Mvc_FormContext$validateGroup(formId, groupName) {
  //Get form element
  var formElement = $get(formId);
  //Get form context
  var formContext = Sys.Mvc.FormContext.getValidationForForm(formElement);
  //Get form fields
  var fields = formContext.fields;
  //Array for errors
  var errors = [];
  //For each field
  for (var i = 0; i &amp;lt; fields.length; i++) {
    var field = fields[i];
    //If field has validation group and its name matches the one we are looking for
    if (field.validationGroup &amp;amp;&amp;amp; field.validationGroup == groupName) {
      //Validate field
      var fieldErrors = field.validate('submit');
      if (fieldErrors) {
        Array.addRange(errors, fieldErrors);
      }
    }
  }
  //Return true it there are no errors, otherwise false
  return (!errors || !errors.length);
}&lt;/pre&gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;And our job is done. Now we can call &lt;em&gt;Sys.Mvc.FormContext.validateGroup('formId', 'validationGroup');&lt;/em&gt; whenever we want to perform partial validation. I have created a sample application which make use of those modification, you can download it from my &lt;a href="https://tpeczek.svn.codeplex.com/svn/trunk/MVC/PartFormValidationExample/"&gt;repository&lt;/a&gt;. If there is a need for same modification for jQuery validation, let me know and I will look into it.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=0og_njCF9UY:0cp9FPbWWsg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=0og_njCF9UY:0cp9FPbWWsg:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/0og_njCF9UY" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/06/partial-forms-validation-in-aspnet-mvc.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><thr:total>10</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-6748298719153211867</guid><pubDate>Fri, 28 May 2010 15:34:00 +0000</pubDate><atom:updated>2011-03-31T10:48:31.642+02:00</atom:updated><title>Using AntiForgeryToken with other verbs than POST (and ActionLinks)</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Today I have found &lt;a href="http://forums.asp.net/t/1562962.aspx"&gt;this&lt;/a&gt; question on &lt;a href="http://forums.asp.net/"&gt;forums.asp.net&lt;/a&gt; and decided to take a look at it. I must warn you, the solution might be considered a little bit hacky.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;So for starters, we have an &lt;em&gt;ActionLink&lt;/em&gt; which looks like this:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;%= Ajax.ActionLink(&amp;quot;Delete&amp;quot;, &amp;quot;AjaxDeleteItem&amp;quot;, new { ItemId = item.ItemId }, new AjaxOptions { Confirm = &amp;quot;Are you sure you want to delete the item?&amp;quot;, HttpMethod = &amp;quot;Delete&amp;quot;, UpdateTargetId = &amp;quot;divList&amp;quot;}) %&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;and we want to secure this &lt;em&gt;Delete&lt;/em&gt; action with &lt;em&gt;AntiForgeryToken&lt;/em&gt;. First we need to add &lt;em&gt;AntiForgeryToken&lt;/em&gt; helper to the view:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;%= Html.AntiForgeryToken() %&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now let's modify our &lt;em&gt;ActionLink&lt;/em&gt;:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;%= Ajax.ActionLink(&amp;quot;Delete&amp;quot;, &amp;quot;AjaxDeleteItem&amp;quot;, new { ItemId = item.ItemId, __RequestVerificationToken = &amp;quot;_&amp;quot; }, new AjaxOptions { Confirm = &amp;quot;Are you sure you want to delete the item?&amp;quot;, HttpMethod = &amp;quot;Delete&amp;quot;, UpdateTargetId = &amp;quot;divList&amp;quot; })%&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Here comes the hacky part. We will use this additional route value (&lt;em&gt;__RequestVerificationToken = &amp;quot;_&amp;quot;&lt;/em&gt;) as a placeholder to inject the value of our &lt;em&gt;AntiForgeryToken&lt;/em&gt; into links &lt;em&gt;href&lt;/em&gt; with a little help of &lt;em&gt;jQuery&lt;/em&gt;:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;$(document).ready(function () {&lt;br /&gt;  //Finding AntiForgeryToken input&lt;br /&gt;  var antiForgeryToken = $('input[name=__RequestVerificationToken]');&lt;br /&gt;  if (antiForgeryToken.length &amp;gt; 0) {&lt;br /&gt;    //Serializing AntiForgeryToken&lt;br /&gt;    var antiForgeryTokenSerialized = antiForgeryToken.serialize();&lt;br /&gt;    //For each anchor in page&lt;br /&gt;    $('a').each(function (index, element) {&lt;br /&gt;      //Replace placeholder with serialized AntiForgeryToken&lt;br /&gt;      $(element).attr('href', $(element).attr('href').replace('__RequestVerificationToken=_', antiForgeryTokenSerialized));&lt;br /&gt;    });&lt;br /&gt;  }&lt;br /&gt;});&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Our job on client side is done, all the links which had our placeholder in their &lt;em&gt;href&lt;/em&gt; now have &lt;em&gt;AntiForgeryToken&lt;/em&gt;. We should now add token verification to the controller action:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;[AcceptVerbs(HttpVerbs.Delete)]&lt;br /&gt;[ValidateAntiForgeryToken]&lt;br /&gt;public ActionResult AjaxDeleteItem(string ItemId)&lt;br /&gt;{&lt;br /&gt;  ...&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;If you would run the code now, you would see that it's not working. That's because &lt;em&gt;AntiForgeryToken&lt;/em&gt; is designed for &lt;em&gt;POST&lt;/em&gt; requests and it expects the token in &lt;em&gt;Request.Form&lt;/em&gt; collection. To work around this we will modify the following line of &lt;em&gt;OnAuthorization&lt;/em&gt; method in &lt;em&gt;ValidateAntiForgeryTokenAttribute&lt;/em&gt; class:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;string formValue = filterContext.HttpContext.Request.Form[fieldName];&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;to this:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;HttpVerbs verb;&lt;br /&gt;//Parse HttpVerb from Request.GetHttpMethodOverride()&lt;br /&gt;if (!Enum.TryParse&amp;lt;HttpVerbs&amp;gt;(filterContext.HttpContext.Request.GetHttpMethodOverride(), true, out verb))&lt;br /&gt;  //If method couldn't be parsed, assume POST&lt;br /&gt;  verb = HttpVerbs.Post;&lt;br /&gt;&lt;br /&gt;//Extract token based on HttpVerb&lt;br /&gt;string formValue = String.Empty;&lt;br /&gt;if (verb == HttpVerbs.Post || verb == HttpVerbs.Put)&lt;br /&gt;  formValue = filterContext.HttpContext.Request.Form[fieldName];&lt;br /&gt;else&lt;br /&gt;  formValue = filterContext.HttpContext.Request.Params[fieldName];&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;After that small change, this workaround works the way we wanted to. The code was tested only in few simple testcases, so it migth contain some flaws.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=0ZW94TXrFo8:SIE8_nJ4Q4A:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=0ZW94TXrFo8:SIE8_nJ4Q4A:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/0ZW94TXrFo8" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/05/using-antiforgerytoken-with-other-verbs.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><thr:total>13</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-798927848385733135</guid><pubDate>Mon, 24 May 2010 00:11:00 +0000</pubDate><atom:updated>2011-03-30T19:18:45.458+02:00</atom:updated><title>jQuery Autocomplete in ASP.NET MVC</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This time I'm going to write about using &lt;a href="http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/"&gt;jQuery Autocomplete plugin&lt;/a&gt; in ASP.NET MVC. If we want to use the plugin, we should reference following JavaScript and CSS:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;link href=&amp;quot;&amp;lt;%= Url.Content(&amp;quot;~/Content/jquery.autocomplete.css&amp;quot;) %&amp;gt;&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;&amp;lt;%= Url.Content(&amp;quot;~/Scripts/jquery-1.4.1.min.js&amp;quot;) %&amp;gt;&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;&amp;lt;%= Url.Content(&amp;quot;~/Scripts/jquery.autocomplete.min.js&amp;quot;) %&amp;gt;&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;We will start by creating simple autocomplete with static data (below JavaScript assumes that there is already a input with type &lt;em&gt;text&lt;/em&gt; and id &lt;em&gt;region&lt;/em&gt;):&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;//Static data for autocomplete&lt;br /&gt;var regions = ['Eastern', 'Western', 'Northern', 'Southern'];&lt;br /&gt;&lt;br /&gt;$(document).ready(function () {&lt;br /&gt;  //Adding autocomplete to region input&lt;br /&gt;  $(&amp;quot;#region&amp;quot;).autocomplete(regions, {&lt;br /&gt;    //Minimum number of characters a user has to type before the autocompleter activates&lt;br /&gt;    minChars: 0,&lt;br /&gt;    //The number of items in the select box&lt;br /&gt;    max: 4,&lt;br /&gt;    //Fill the input while still selecting a value&lt;br /&gt;    autoFill: true,&lt;br /&gt;    //Only suggested values are valid&lt;br /&gt;    mustMatch: true,&lt;br /&gt;    //The comparison doesn't looks inside &lt;br /&gt;    matchContains: false&lt;br /&gt;  });&lt;br /&gt;});&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we will extend &lt;em&gt;regions&lt;/em&gt; so it contains objects with &lt;em&gt;regionId&lt;/em&gt; and &lt;em&gt;regionDescription&lt;/em&gt; properties. We want to display the &lt;em&gt;regionDescription&lt;/em&gt; in autocomplete and put selected &lt;em&gt;regionId&lt;/em&gt; into input of type &lt;em&gt;hidden&lt;/em&gt;. To achieve this, we will use autocomplete callbacks for formatting data and result. But first let's change markup:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;%: Html.Hidden(&amp;quot;regionId&amp;quot;, -1) %&amp;gt;&lt;br /&gt;&amp;lt;label for=&amp;quot;regionDescription&amp;quot;&amp;gt;Region:&amp;lt;/label&amp;gt; &amp;lt;%: Html.TextBox(&amp;quot;regionDescription&amp;quot;)%&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;And here is modified JavaScript:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;//Static data for autocomplete&lt;br /&gt;var regions = [&lt;br /&gt;  { regionId: 1, regionDescription: 'Eastern' },&lt;br /&gt;  { regionId: 2, regionDescription: 'Western' },&lt;br /&gt;  { regionId: 3, regionDescription: 'Northern' },&lt;br /&gt;  { regionId: 4, regionDescription: 'Southern' }&lt;br /&gt;];&lt;br /&gt;&lt;br /&gt;$(document).ready(function () {&lt;br /&gt;  //Adding autocomplete to region input&lt;br /&gt;  $(&amp;quot;#regionDescription&amp;quot;).autocomplete(regions, {&lt;br /&gt;    //Minimum number of characters a user has to type before the autocompleter activates&lt;br /&gt;    minChars: 0,&lt;br /&gt;    //The number of items in the select box&lt;br /&gt;    max: 4,&lt;br /&gt;    //Fill the input while still selecting a value&lt;br /&gt;    autoFill: true,&lt;br /&gt;    //Only suggested values are valid&lt;br /&gt;    mustMatch: true,&lt;br /&gt;    //The comparison doesn't looks inside &lt;br /&gt;    matchContains: false,&lt;br /&gt;    //Callback which will format items for autocomplete list&lt;br /&gt;    formatItem: function (data, index, max) {&lt;br /&gt;      //Display only descriptions in list&lt;br /&gt;      return data.regionDescription;&lt;br /&gt;    },&lt;br /&gt;    //Callback which will format items for matching&lt;br /&gt;    formatMatch: function (data, index, max) {&lt;br /&gt;      //Match only descriptions&lt;br /&gt;      return data.regionDescription;&lt;br /&gt;    },&lt;br /&gt;    //Callback which will format result&lt;br /&gt;    formatResult: function (data, index, max) {&lt;br /&gt;      //Display only description as result&lt;br /&gt;      return data.regionDescription;&lt;br /&gt;    }&lt;br /&gt;  //Callback which will be called when user chooses value&lt;br /&gt;  }).result(function (event, data, formatted) {&lt;br /&gt;    //Set region id as hidden input value&lt;br /&gt;    if (data)&lt;br /&gt;      $(&amp;quot;#regionId&amp;quot;).val(data.regionId);&lt;br /&gt;    else&lt;br /&gt;      $(&amp;quot;#regionId&amp;quot;).val('-1');&lt;br /&gt;  });&lt;br /&gt;});&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;What if we want to achieve the same behavior, but with remotely loaded data? We should start by adding markup for new inputs:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;%: Html.Hidden(&amp;quot;territoryId&amp;quot;, -1)%&amp;gt;&lt;br /&gt;&amp;lt;label for=&amp;quot;territoryDescription&amp;quot;&amp;gt;Territory:&amp;lt;/label&amp;gt; &amp;lt;%: Html.TextBox(&amp;quot;territoryDescription&amp;quot;)%&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;The JavaScript isn't that much different, we just need to pass URL instead of array with data (you can also adjust local cache size):&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;//Adding autocomplete to territoryDescription input&lt;br /&gt;$(&amp;quot;#territoryDescription&amp;quot;).autocomplete('&amp;lt;%: Url.Action(&amp;quot;Territories&amp;quot;, &amp;quot;Home&amp;quot;) %&amp;gt;', {&lt;br /&gt;  //Don't fill the input while still selecting a value&lt;br /&gt;  autoFill: false,&lt;br /&gt;  //Only suggested values are valid&lt;br /&gt;  mustMatch: true,&lt;br /&gt;  //The comparison doesn't looks inside &lt;br /&gt;  matchContains: false,&lt;br /&gt;  //The number of query results to store in cache&lt;br /&gt;  cacheLength: 12,&lt;br /&gt;  //Callback wich will format items for autocomplete list&lt;br /&gt;  formatItem: function (data, index, max) {&lt;br /&gt;    //Display only descriptions in list&lt;br /&gt;    return data[1];&lt;br /&gt;  },&lt;br /&gt;  //Callback which will format items for matching&lt;br /&gt;  formatMatch: function (data, index, max) {&lt;br /&gt;    //Match only descriptions&lt;br /&gt;    return data[1];&lt;br /&gt;  },&lt;br /&gt;  //Callback which will format result&lt;br /&gt;  formatResult: function (data, index, max) {&lt;br /&gt;    //Display only description as result&lt;br /&gt;    return data[1];&lt;br /&gt;  }&lt;br /&gt;//Callback which will be called when user chooses value&lt;br /&gt;}).result(function (event, data, formatted) {&lt;br /&gt;  //Set territory id as hidden input value&lt;br /&gt;  if (data)&lt;br /&gt;    $(&amp;quot;#territoryId&amp;quot;).val(data[0]);&lt;br /&gt;  else&lt;br /&gt;    $(&amp;quot;#territoryId&amp;quot;).val('-1');&lt;br /&gt;});&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Controller action will receive three parameters: &lt;em&gt;q&lt;/em&gt; - the string we should search for, &lt;em&gt;limit&lt;/em&gt; - maximum number of items we should return (equal to &lt;em&gt;max&lt;/em&gt; option) and &lt;em&gt;timestamp&lt;/em&gt;. The plugin is expecting quite unusual response. It should be a string, where &lt;em&gt;'\n'&lt;/em&gt; is a row delimeter and &lt;em&gt;'|'&lt;/em&gt; is cells separator. So the action will look like this (I will skip database access code):&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;public ContentResult Territories(string q, int limit, Int64 timestamp)&lt;br /&gt;{&lt;br /&gt;  StringBuilder responseContentBuilder = new StringBuilder();&lt;br /&gt;  IQueryable&amp;lt;Territory&amp;gt; territories = _repository.GetTerritories(q, limit);&lt;br /&gt;  foreach (Territory territory in territories)&lt;br /&gt;    responseContentBuilder.Append(String.Format(&amp;quot;{0}|{1}\n&amp;quot;, territory.TerritoryID, territory.TerritoryDescription));&lt;br /&gt;&lt;br /&gt;  return Content(responseContentBuilder.ToString());&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;So our autocomplete is now populated from server. Lets take it one step further, and make &lt;em&gt;territory&lt;/em&gt; dependant on &lt;em&gt;region&lt;/em&gt;. We will use &lt;em&gt;extraParams&lt;/em&gt; for this:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;//Adding autocomplete to territoryDescription input&lt;br /&gt;$(&amp;quot;#territoryDescription&amp;quot;).autocomplete('&amp;lt;%: Url.Action(&amp;quot;Territories&amp;quot;, &amp;quot;Home&amp;quot;) %&amp;gt;', {&lt;br /&gt;  //Don't fill the input while still selecting a value&lt;br /&gt;  autoFill: false,&lt;br /&gt;  //Only suggested values are valid&lt;br /&gt;  mustMatch: true,&lt;br /&gt;  //The comparison doesn't looks inside &lt;br /&gt;  matchContains: false,&lt;br /&gt;  //The number of query results to store in cache&lt;br /&gt;  cacheLength: 12,&lt;br /&gt;  //Extra parameters which will be put into query string&lt;br /&gt;  extraParams: {&lt;br /&gt;    regionId: function () { return $(&amp;quot;#regionId&amp;quot;).val(); }&lt;br /&gt;  },&lt;br /&gt;  //Callback which will format items for autocomplete list&lt;br /&gt;  formatItem: function (data, index, max) {&lt;br /&gt;  //Display only descriptions in list&lt;br /&gt;    return data[1];&lt;br /&gt;  },&lt;br /&gt;  //Callback which will format items for matching&lt;br /&gt;  formatMatch: function (data, index, max) {&lt;br /&gt;    //Match only descriptions&lt;br /&gt;    return data[1];&lt;br /&gt;  },&lt;br /&gt;  //Callback which will format result&lt;br /&gt;  formatResult: function (data, index, max) {&lt;br /&gt;    //Display only description as result&lt;br /&gt;    return data[1];&lt;br /&gt;  }&lt;br /&gt;//Callback which will be called when user chooses value&lt;br /&gt;}).result(function (event, data, formatted) {&lt;br /&gt;  //Set territory id as hidden input value&lt;br /&gt;  if (data)&lt;br /&gt;    $(&amp;quot;#territoryId&amp;quot;).val(data[0]);&lt;br /&gt;  else&lt;br /&gt;    $(&amp;quot;#territoryId&amp;quot;).val('-1')&lt;br /&gt;});&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;After that change we will receive on more parameter in our action:&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;public ContentResult Territories(string q, int regionId, int limit, Int64 timestamp)&lt;br /&gt;{&lt;br /&gt;  StringBuilder responseContentBuilder = new StringBuilder();&lt;br /&gt;  IQueryable&amp;lt;Territory&amp;gt; territories = _repository.GetTerritories(regionId, q, limit);&lt;br /&gt;  foreach (Territory territory in territories)&lt;br /&gt;    responseContentBuilder.Append(String.Format(&amp;quot;{0}|{1}\n&amp;quot;, territory.TerritoryID, territory.TerritoryDescription));&lt;br /&gt;&lt;br /&gt;  return Content(responseContentBuilder.ToString());&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;This way we have finished our simple sample. There are few more interesting options in this plugin (for example you can attach it to &lt;em&gt;textarea&lt;/em&gt; and/or allow multiply selection). Our sample application looks like this:&lt;/span&gt;&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;br /&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://1.bp.blogspot.com/_c2mfEqrjR68/S_nAyq-DzDI/AAAAAAAAAF8/jqFer5-DlEg/s1600/autocomplete.png" imageanchor="1"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_c2mfEqrjR68/S_nAyq-DzDI/AAAAAAAAAF8/jqFer5-DlEg/s320/autocomplete.png" gu="true" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;You can download source code from &lt;a href="http://tpeczek.codeplex.com/releases/view/45802"&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=d4bMg5cz3qQ:hBg77WQPdDI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=d4bMg5cz3qQ:hBg77WQPdDI:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/d4bMg5cz3qQ" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/05/jquery-autocomplete-in-aspnet-mvc.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_c2mfEqrjR68/S_nAyq-DzDI/AAAAAAAAAF8/jqFer5-DlEg/s72-c/autocomplete.png" height="72" width="72" /><thr:total>7</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-262957011665692973</guid><pubDate>Sun, 16 May 2010 19:18:00 +0000</pubDate><atom:updated>2011-03-30T16:38:53.915+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">jquery</category><category domain="http://www.blogger.com/atom/ns#">asp.net</category><category domain="http://www.blogger.com/atom/ns#">ajax</category><category domain="http://www.blogger.com/atom/ns#">treeview</category><category domain="http://www.blogger.com/atom/ns#">asynchronous</category><title>Asynchronous TreeView in ASP.NET WebForms</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Some time ago I have &lt;a href="http://tpeczek.blogspot.com/2010/01/asynchronous-treeview-in-aspnet-mvc.html/"&gt;written&lt;/a&gt; about using &lt;a href="http://bassistance.de/jquery-plugins/jquery-plugin-treeview/"&gt;jQuery TreeView plugin&lt;/a&gt; for creating an asynchronous &lt;em&gt;TreeView&lt;/em&gt; in ASP.NET MVC. Recently I had to use the same plugin in WebForms application, so I decided to share my experience.&lt;/span&gt; &lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;First let's reference all JavaScript and CSS needed:&lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;script src=&amp;quot;Scripts/jquery-1.4.1.min.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;Scripts/jquery.treeview.min.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;Scripts/jquery.treeview.async.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;link href=&amp;quot;~/Styles/jquery.treeview.css&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;We should also add the markup for &lt;em&gt;TreeView&lt;/em&gt; (an empty list):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;ul id=&amp;quot;trFileBrowser&amp;quot;&amp;gt;&amp;lt;/ul&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we should provide data for &lt;em&gt;TreeView&lt;/em&gt;, there are generally two approaches in which we can do that.&lt;/span&gt;&lt;h5 style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif;text-decoration: underline"&gt;WebService approach&lt;/h5&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;If we want to use WebService as the data source, we should start by adding an &lt;em&gt;Ajax-enabled WCF Service&lt;/em&gt; to the project:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;[ServiceContract(Namespace = &amp;quot;AsyncTreeViewExample&amp;quot;)]&lt;br /&gt;[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]&lt;br /&gt;public class TreeView&lt;br /&gt;{&lt;br /&gt;  ...&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;and enabling the Web programming model for this service (in &lt;em&gt;web.config&lt;/em&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;system.serviceModel&amp;gt;&lt;br /&gt;  &amp;lt;behaviors&amp;gt;&lt;br /&gt;    &amp;lt;endpointBehaviors&amp;gt;&lt;br /&gt;      &amp;lt;behavior name=&amp;quot;AsyncTreeViewExample.TreeViewAspNetAjaxBehavior&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;webHttp /&amp;gt;&lt;br /&gt;      &amp;lt;/behavior&amp;gt;&lt;br /&gt;    &amp;lt;/endpointBehaviors&amp;gt;&lt;br /&gt;  &amp;lt;/behaviors&amp;gt;&lt;br /&gt;  &amp;lt;serviceHostingEnvironment aspNetCompatibilityEnabled=&amp;quot;true&amp;quot; multipleSiteBindingsEnabled=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;  &amp;lt;services&amp;gt;&lt;br /&gt;    &amp;lt;service name=&amp;quot;AsyncTreeViewExample.TreeView&amp;quot;&amp;gt;&lt;br /&gt;      &amp;lt;endpoint address=&amp;quot;&amp;quot; behaviorConfiguration=&amp;quot;AsyncTreeViewExample.TreeViewAspNetAjaxBehavior&amp;quot; binding=&amp;quot;webHttpBinding&amp;quot; contract=&amp;quot;AsyncTreeViewExample.TreeView&amp;quot; /&amp;gt;&lt;br /&gt;    &amp;lt;/service&amp;gt;&lt;br /&gt;  &amp;lt;/services&amp;gt;&lt;br /&gt;&amp;lt;/system.serviceModel&amp;gt;&lt;br /&gt;...&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;In order to write WebService method properly, we need to remember that plugin performs GET request with &lt;em&gt;application/x-www-form-urlencoded&lt;/em&gt; content type and expects bare JSON serialized array in response. Knowing all that, the method should look like this (&lt;em&gt;TreeViewNode&lt;/em&gt; class was described in &lt;a href="http://tpeczek.blogspot.com/2010/01/asynchronous-treeview-in-aspnet-mvc.html/"&gt;previous post&lt;/a&gt; about this plugin):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;&lt;br /&gt;[OperationContract]&lt;br /&gt;//Accept GET request and return bare JSON serialized result&lt;br /&gt;[WebInvoke(Method = &amp;quot;GET&amp;quot;, BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]&lt;br /&gt;public List&amp;lt;TreeViewNode&amp;gt; FileBrowserData(string root)&lt;br /&gt;{&lt;br /&gt;  DirectoryInfo rootDirectory = null;&lt;br /&gt;  if (root == &amp;quot;source&amp;quot;)&lt;br /&gt;    rootDirectory = new DirectoryInfo(@&amp;quot;E:\&amp;quot;);&lt;br /&gt;  else&lt;br /&gt;    rootDirectory = new DirectoryInfo(root);&lt;br /&gt;  &lt;br /&gt;  var directoryChildren = from child in rootDirectory.GetFileSystemInfos()&lt;br /&gt;                          orderby child is DirectoryInfo descending&lt;br /&gt;                          select child;&lt;br /&gt;&lt;br /&gt;  List&amp;lt;TreeViewNode&amp;gt; nodes = new List&amp;lt;TreeViewNode&amp;gt;();&lt;br /&gt;  foreach (FileSystemInfo directoryChild in directoryChildren)&lt;br /&gt;  {&lt;br /&gt;    bool isDirectory = directoryChild is DirectoryInfo;&lt;br /&gt;    nodes.Add(new TreeViewNode()&lt;br /&gt;    {&lt;br /&gt;      id = directoryChild.FullName,&lt;br /&gt;      text = directoryChild.Name,&lt;br /&gt;      classes = isDirectory ? &amp;quot;folder&amp;quot; : &amp;quot;file&amp;quot;,&lt;br /&gt;      hasChildren = isDirectory&lt;br /&gt;    });&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return nodes;&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Last thing to do in this approach is adding some JavaScript for initialization purposes:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;  $(document).ready(function () {&lt;br /&gt;    $('#trFileBrowser').treeview({&lt;br /&gt;      url: '&amp;lt;% = ResolveClientUrl(&amp;quot;~/TreeView.svc/FileBrowserData&amp;quot;) %&amp;gt;'&lt;br /&gt;    });&lt;br /&gt;  });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;h5 style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif;text-decoration: underline"&gt;PageMethod approach&lt;/h5&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Using PageMethod as a source of data is a little bit more tricky. First of all PageMethods requires request to have &lt;em&gt;application/json&lt;/em&gt; content type (so all the parameters have to be properly JSON serialized). Also PageMethod always returns response with wrapped body. There are three ways in which we can workaround this.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;First way is to modify the plugin in such a way that it will work with PageMethod requirements (I would recommend this way, as others should be considered nasty workarounds). This is modified &lt;em&gt;load&lt;/em&gt; funtion from &lt;em&gt;jquery.treeview.async.js&lt;/em&gt; (I'm also changing request from GET to POST here):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;function load(settings, root, child, container) {&lt;br /&gt;  $.ajax({&lt;br /&gt;    //Changing request to POST&lt;br /&gt;    type: &amp;quot;POST&amp;quot;,&lt;br /&gt;    url: settings.url,&lt;br /&gt;    //Required content type&lt;br /&gt;    contentType: 'application/json; charset=utf-8',&lt;br /&gt;    //Properly JSON serialized data&lt;br /&gt;    data: '{&amp;quot;root&amp;quot;: &amp;quot;' + root + '&amp;quot;}',&lt;br /&gt;    dataType: 'json',&lt;br /&gt;    success: function(response) {&lt;br /&gt;      function createNode(parent) {&lt;br /&gt;        var current = $(&amp;quot;&amp;lt;li/&amp;gt;&amp;quot;).attr(&amp;quot;id&amp;quot;, this.id || &amp;quot;&amp;quot;).html(&amp;quot;&amp;lt;span&amp;gt;&amp;quot; + this.text + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;).appendTo(parent);&lt;br /&gt;        if (this.classes) {&lt;br /&gt;          current.children(&amp;quot;span&amp;quot;).addClass(this.classes);&lt;br /&gt;        }&lt;br /&gt;        if (this.expanded) {&lt;br /&gt;          current.addClass(&amp;quot;open&amp;quot;);&lt;br /&gt;        }&lt;br /&gt;        if (this.hasChildren || this.children &amp;amp;&amp;amp; this.children.length) {&lt;br /&gt;          var branch = $(&amp;quot;&amp;lt;ul/&amp;gt;&amp;quot;).appendTo(current);&lt;br /&gt;          if (this.hasChildren) {&lt;br /&gt;            current.addClass(&amp;quot;hasChildren&amp;quot;);&lt;br /&gt;            createNode.call({&lt;br /&gt;              text:&amp;quot;placeholder&amp;quot;,&lt;br /&gt;              id:&amp;quot;placeholder&amp;quot;,&lt;br /&gt;              children:[]&lt;br /&gt;              }, branch);&lt;br /&gt;          }&lt;br /&gt;          if (this.children &amp;amp;&amp;amp; this.children.length) {&lt;br /&gt;            $.each(this.children, createNode, [branch])&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;      //Accessing wrapped array&lt;br /&gt;      $.each(response.d, createNode, [child]);&lt;br /&gt;      $(container).treeview({add: child});&lt;br /&gt;    }&lt;br /&gt;  });&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;After that we just need a regular PageMethod:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;[System.Web.Services.WebMethod]&lt;br /&gt;public static List&amp;lt;TreeViewNode&amp;gt; FileBrowserData(string root)&lt;br /&gt;{&lt;br /&gt;  //Method body is the same as in WebService&lt;br /&gt;  ...&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;and initalization JavaScript:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;  $(document).ready(function () {&lt;br /&gt;    $('#trFileBrowser').treeview({&lt;br /&gt;      url: '&amp;lt;% = ResolveClientUrl(&amp;quot;~/PageMethodPlugin.aspx/FileBrowserData&amp;quot;) %&amp;gt;'&lt;br /&gt;    });&lt;br /&gt;  });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Second way we can call a 'client-side workaround'. The idea is to change some default settings for all Ajax requests (it's nasty and I wouldn't recommend using it):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;  $(document).ready(function () {&lt;br /&gt;    //Default callback for creating the XMLHttpRequest object&lt;br /&gt;    var xhr = $.ajaxSettings.xhr;&lt;br /&gt;&lt;br /&gt;    //Changing default values for all Ajax requests&lt;br /&gt;    $.ajaxSetup({&lt;br /&gt;      //Required content type&lt;br /&gt;      contentType: 'application/json; charset=utf-8',&lt;br /&gt;      //New callback for creating the XMLHttpRequest object&lt;br /&gt;      xhr: function () {&lt;br /&gt;        //Wrapping url parameters with '&amp;quot;'&lt;br /&gt;        if (this.url.indexOf('=') &amp;gt;= 0) {&lt;br /&gt;          this.url = this.url.replace(/=/g, '=&amp;quot;') + '&amp;quot;';&lt;br /&gt;        }&lt;br /&gt;        //Calling default callback&lt;br /&gt;        return xhr.call(this);&lt;br /&gt;      },&lt;br /&gt;      //Sanitize the response (remove wrapping)&lt;br /&gt;      dataFilter: function (data, dataType) {&lt;br /&gt;        if (dataType == &amp;quot;json&amp;quot;) {&lt;br /&gt;          var result = $.parseJSON(data);&lt;br /&gt;          if (result.d) {&lt;br /&gt;            return result.d;&lt;br /&gt;          } else {&lt;br /&gt;            return data;&lt;br /&gt;          }&lt;br /&gt;        } else {&lt;br /&gt;          return data;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    });&lt;br /&gt;    $('#trFileBrowser').treeview({&lt;br /&gt;      url: '&amp;lt;% = ResolveClientUrl(&amp;quot;~/PageMethodClient.aspx/FileBrowserData&amp;quot;) %&amp;gt;'&lt;br /&gt;    });&lt;br /&gt;  });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;We also have to allow GET verb on PageMethod:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;&lt;br /&gt;[System.Web.Services.WebMethod]&lt;br /&gt;[System.Web.Script.Services.ScriptMethod(UseHttpGet = true)]&lt;br /&gt;public static List&amp;lt;TreeViewNode&amp;gt; FileBrowserData(string root)&lt;br /&gt;{&lt;br /&gt;  //Method body is the same as in WebService&lt;br /&gt;  ...&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Third way is 'server-side workaround'. We will write PageMethod in a little bit different way, so it will work with &lt;em&gt;TreeView&lt;/em&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: csharp;"&gt;[System.Web.Services.WebMethod]&lt;br /&gt;[System.Web.Script.Services.ScriptMethod(UseHttpGet = true)]&lt;br /&gt;//Method doesn't take any parameters and return anything&lt;br /&gt;public static void FileBrowserData()&lt;br /&gt;{&lt;br /&gt;  //We are getting 'root' directly from request params&lt;br /&gt;  string root = HttpContext.Current.Request.Params.Get(&amp;quot;root&amp;quot;);&lt;br /&gt;&lt;br /&gt;  //Nodes generation code is the same as in other cases&lt;br /&gt;  ...&lt;br /&gt;&lt;br /&gt;  //We are serializing nodes&lt;br /&gt;  JavaScriptSerializer serializer = new JavaScriptSerializer();&lt;br /&gt;  string nodesSerialized = serializer.Serialize(nodes);&lt;br /&gt;&lt;br /&gt;  //And writing them directly into response&lt;br /&gt;  HttpContext.Current.Response.Clear();&lt;br /&gt;  HttpContext.Current.Response.ContentType = &amp;quot;application/json; charset=utf-8&amp;quot;;&lt;br /&gt;  HttpContext.Current.Response.AddHeader(&amp;quot;Content-Length&amp;quot;, nodesSerialized.Length.ToString());&lt;br /&gt;  HttpContext.Current.Response.AddHeader(&amp;quot;Connection&amp;quot;, &amp;quot;Close&amp;quot;);&lt;br /&gt;  HttpContext.Current.Response.Write(nodesSerialized);&lt;br /&gt;  HttpContext.Current.Response.Flush();&lt;br /&gt;}&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;What is left is few lines of JavaScript:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;  $(document).ready(function () {&lt;br /&gt;    //Changing default values for all Ajax requests&lt;br /&gt;    $.ajaxSetup({&lt;br /&gt;      //Required content type&lt;br /&gt;      contentType: 'application/json; charset=utf-8'&lt;br /&gt;    });&lt;br /&gt;    $('#trFileBrowser').treeview({&lt;br /&gt;      url: '&amp;lt;% = ResolveClientUrl(&amp;quot;~/PageMethodClient.aspx/FileBrowserData&amp;quot;) %&amp;gt;'&lt;br /&gt;    });&lt;br /&gt;  });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we have all approaches covered, the result of this work looks like this:&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_c2mfEqrjR68/S_A8wgD0j3I/AAAAAAAAAFo/t0yEFKcGJ2Y/s1600/treeview.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_c2mfEqrjR68/S_A8wgD0j3I/AAAAAAAAAFo/t0yEFKcGJ2Y/s320/treeview.jpg" wt="true" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;You can download source code from &lt;a href="http://tpeczek.codeplex.com/releases/view/45363"&gt;repository&lt;/a&gt;.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=3qJ99WpgskM:BvHQ1o7xur0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=3qJ99WpgskM:BvHQ1o7xur0:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/3qJ99WpgskM" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/05/asynchronous-treeview-in-aspnet.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_c2mfEqrjR68/S_A8wgD0j3I/AAAAAAAAAFo/t0yEFKcGJ2Y/s72-c/treeview.jpg" height="72" width="72" /><thr:total>6</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-4250896466406892933</guid><pubDate>Thu, 29 Apr 2010 22:13:00 +0000</pubDate><atom:updated>2010-05-18T12:36:11.017+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">client-side validation</category><category domain="http://www.blogger.com/atom/ns#">ajax</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><title>Making ASP.NET MVC 2 client side validation work with AJAX loaded forms</title><description>&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Few days ago I wrote a post in &lt;a href="http://forums.asp.net/t/1552149.aspx"&gt;this&lt;/a&gt; thread on &lt;a href="http://forums.asp.net/"&gt;forums.asp.net&lt;/a&gt;. In one of the posts &lt;a href="http://forums.asp.net/members/vazavi.aspx"&gt;vazavi&lt;/a&gt; noticed, that client side validation works only until you reload form using AJAX. I decided to take a deeper look at this. After few hours I have found a solution. The solution depends on which client side validation script you are using (the one which works with jQuery or the one which not).&lt;/span&gt;  &lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;First I will go with the one which doesn't use jQuery. To make it work we need to write one function (I have just added it to &lt;em&gt;MicrosoftMvcValidation.js&lt;/em&gt;):&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;Sys.Mvc.FormContext.OnSuccessEnableClientValidation = function (ajaxContext) {
  //Getting the update target container
  var updateTarget = document.getElementById(ajaxContext.$4.id);
  //Getting all script elements in it (script elements injected with innerHtml are not executed)
  var mvcClientValidationMetadataOldScripts = updateTarget.getElementsByTagName('script');
  var mvcClientValidationMetadataNewScripts = [];
  //For every script element
  while (mvcClientValidationMetadataOldScripts.length &amp;gt; 0) {
    //Create a new one
    var mvcClientValidationMetadataNewScript = document.createElement('script');
    mvcClientValidationMetadataNewScript.type = 'text/javascript';
    mvcClientValidationMetadataNewScript.text = mvcClientValidationMetadataOldScripts[0].text;
    //Add it to collection
    mvcClientValidationMetadataNewScripts.push(mvcClientValidationMetadataNewScript);
    //And remove old one
    updateTarget.removeChild(mvcClientValidationMetadataOldScripts[0]);
  }
  //For every new script element
  while (mvcClientValidationMetadataNewScripts.length &amp;gt; 0) {
    //Append it to update target container, this way they will be executed and generate needed metadata
    updateTarget.appendChild(mvcClientValidationMetadataNewScripts.pop());
  }
  //Calling Microsoft validation initialization for new metadata
  Sys.Mvc.FormContext._Application_Load();
}
&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;&lt;/span&gt;&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now we can use our new function as OnSuccess handler for &lt;em&gt;Ajax.BeginForm&lt;/em&gt;:&lt;/span&gt; &lt;br /&gt;
&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;% Html.EnableClientValidation(); %&amp;gt;
&amp;lt;% using (Ajax.BeginForm("...", "...", null, new AjaxOptions() { UpdateTargetId = "...", OnSuccess = "Sys.Mvc.FormContext.OnSuccessEnableClientValidation" }, new { id = "..." })) { %&amp;gt;
  ...
&amp;lt;% } %&amp;gt;
&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;Now it should work. Let's do the same for &lt;em&gt;MicrosoftMvcJQueryValidation.js&lt;/em&gt;. We will add the following function inside of it:&lt;/span&gt; &lt;br /&gt;
&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: js;"&gt;function __MVC_OnSuccessEnableClientValidation(ajaxContext) {
  //Getting the update target container
  var updateTarget = document.getElementById(ajaxContext.$4.id);
  //Getting all script elements in it (script elements injected with innerHtml are not executed)
  var mvcClientValidationMetadataOldScripts = updateTarget.getElementsByTagName('script');
  var mvcClientValidationMetadataNewScripts = [];
  //For every script element
  while (mvcClientValidationMetadataOldScripts.length &gt; 0) {
    //Create a new one
    var mvcClientValidationMetadataNewScript = document.createElement('script');
    mvcClientValidationMetadataNewScript.type = 'text/javascript';
    mvcClientValidationMetadataNewScript.text = mvcClientValidationMetadataOldScripts[0].text;
    //Add it to collection
    mvcClientValidationMetadataNewScripts.push(mvcClientValidationMetadataNewScript);
    //And remove old one
    updateTarget.removeChild(mvcClientValidationMetadataOldScripts[0]);
  }
  //For every new script element
  while (mvcClientValidationMetadataNewScripts.length &gt; 0) {
    //Append it to update target container, this way they will be executed and generate needed metadata
    updateTarget.appendChild(mvcClientValidationMetadataNewScripts.pop());
  }
  //Getting new metadata
  var allFormOptions = window.mvcClientValidationMetadata;
  if (allFormOptions) {
    //For every form in metadata
    while (allFormOptions.length &gt; 0) {
      //Enable validation for form based on metadata
      var thisFormOptions = allFormOptions.pop();
      __MVC_EnableClientValidation(thisFormOptions);
    }
  }
}
&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;We can use this function in the same way as previous one:&lt;/span&gt; &lt;br /&gt;
&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, courier, monospace; font-size: x-small"&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;% Html.EnableClientValidation(); %&amp;gt;
&amp;lt;% using (Ajax.BeginForm("...", "...", null, new AjaxOptions() { UpdateTargetId = "...", OnSuccess = "__MVC_OnSuccessEnableClientValidation" }, new { id = "..." })) { %&amp;gt;
  ...
&amp;lt;% } %&amp;gt;
&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: times, &amp;quot;Times New Roman&amp;quot;, serif"&gt;I can't say that this solution has been tested in every possible scenario, so if you find any problems with it, just let me know.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=7WwqkPCgT7k:u0jHo4cfYko:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=7WwqkPCgT7k:u0jHo4cfYko:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/7WwqkPCgT7k" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/04/making-aspnet-mvc-2-client-side.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><thr:total>16</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-5566544203494390224</guid><pubDate>Sun, 18 Apr 2010 17:56:00 +0000</pubDate><atom:updated>2010-05-12T18:47:19.025+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">antiforgerytoken</category><category domain="http://www.blogger.com/atom/ns#">ajax</category><category domain="http://www.blogger.com/atom/ns#">jquery validation</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><title>'Unobtrusive' asynchronous Form in ASP.NET MVC 2</title><description>&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;Some time ago I have written a &lt;a href="http://tpeczek.blogspot.com/2010/02/unobtrusive-asynchronous-form-in-aspnet.html"&gt;post&lt;/a&gt; about creating asynchronous form with client-side validation in ASP.NET MVC. Since then few things have been changed.&amp;nbsp;Now we&amp;nbsp;have ASP.NET MVC 2 with built in client-side validation. So it's time to rewrite that sample (but we are still going to use &lt;a href="http://bassistance.de/jquery-plugins/jquery-plugin-validation/"&gt;jQuery Validation plugin&lt;/a&gt;).&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;First let's remove all the javascript from our view, and leave only those script references:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;script&lt;/span&gt; &lt;span style="color: red;"&gt;src&lt;/span&gt;&lt;span style="color: blue;"&gt;="&lt;/span&gt;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;= Url.Content("~/Scripts/jquery-1.4.1.min.js") &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;"&lt;/span&gt; &lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;="text/javascript"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;script&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;script&lt;/span&gt; &lt;span style="color: red;"&gt;src&lt;/span&gt;&lt;span style="color: blue;"&gt;="&lt;/span&gt;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;= Url.Content("~/Scripts/jquery.validate.min.js") &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;"&lt;/span&gt; &lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;="text/javascript"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;script&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;script&lt;/span&gt; &lt;span style="color: red;"&gt;src&lt;/span&gt;&lt;span style="color: blue;"&gt;="&lt;/span&gt;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;= Url.Content("~/Scripts/MicrosoftAjax.js") &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;"&lt;/span&gt; &lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;="text/javascript"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;script&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;script&lt;/span&gt; &lt;span style="color: red;"&gt;src&lt;/span&gt;&lt;span style="color: blue;"&gt;="&lt;/span&gt;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;= Url.Content("~/Scripts/MicrosoftMvcAjax.js") &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;"&lt;/span&gt; &lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;="text/javascript"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;script&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;script&lt;/span&gt; &lt;span style="color: red;"&gt;src&lt;/span&gt;&lt;span style="color: blue;"&gt;="&lt;/span&gt;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;= Url.Content("~/Scripts/MicrosoftMvcJQueryValidation.js") &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;"&lt;/span&gt; &lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;="text/javascript"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;script&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;Now we will move our form to user control and make some changes in it:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;@&lt;/span&gt; &lt;span style="color: #b45f06;"&gt;Control&lt;/span&gt; &lt;span style="color: red;"&gt;Language&lt;/span&gt;&lt;span style="color: blue;"&gt;="C#"&lt;/span&gt; &lt;span style="color: red;"&gt;Inherits&lt;/span&gt;&lt;span style="color: blue;"&gt;="System.Web.Mvc.ViewUserControl&amp;lt;...&amp;gt;"&lt;/span&gt; &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt; Html.EnableClientValidation(); &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (Model.UserRegistered) { &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;User successfully registered.&lt;br /&gt;
&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="color: blue;"&gt;else&lt;/span&gt; { &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color: blue;"&gt;using&lt;/span&gt; (Ajax.BeginForm(&lt;span style="color: #b45f06;"&gt;"AsynchronousForm"&lt;/span&gt;, &lt;span style="color: #b45f06;"&gt;"Home"&lt;/span&gt;, &lt;span style="color: blue;"&gt;null&lt;/span&gt;, &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;AjaxOptions&lt;/span&gt;() { UpdateTargetId = &lt;span style="color: #b45f06;"&gt;"dvAccountInformationFormContainer"&lt;/span&gt; },&amp;nbsp;&lt;span style="color: blue;"&gt;new&lt;/span&gt; { id = &lt;span style="color: #b45f06;"&gt;"frmRegister"&lt;/span&gt; })) { &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.AntiForgeryToken() &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;div&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;fieldset&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;legend&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;Account Information&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;legend&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;p&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.LabelFor(value =&amp;gt; Model.UserName)&amp;nbsp;&lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.TextBoxFor(value =&amp;gt; Model.UserName) &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.ValidationMessageFor(value =&amp;gt; Model.UserName) &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;p&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;p&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.LabelFor(value =&amp;gt; Model.Email)&amp;nbsp;&lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.TextBoxFor(value =&amp;gt; Model.Email) &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.ValidationMessageFor(value =&amp;gt; Model.Email) &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;p&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;p&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.LabelFor(value =&amp;gt; Model.Password)&amp;nbsp;&lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.TextBoxFor(value =&amp;gt; Model.Password) &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.ValidationMessageFor(value =&amp;gt; Model.Password) &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;p&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;p&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.LabelFor(value =&amp;gt; Model.ConfirmPassword)&amp;nbsp;&lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.TextBoxFor(value =&amp;gt; Model.ConfirmPassword) &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.ValidationMessageFor(value =&amp;gt; Model.ConfirmPassword) &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;p&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;p&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;input&lt;/span&gt; &lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;="submit"&lt;/span&gt; &lt;span style="color: red;"&gt;value&lt;/span&gt;&lt;span style="color: blue;"&gt;="Register" /&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;p&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;fieldset&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;div&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;div&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;As you can see I have added &lt;em&gt;Html.EnableClientValidation();&lt;/em&gt; to the markup - this will enable native client-side validation. I have also changed &lt;em&gt;Html.BeginForm&lt;/em&gt; into &lt;em&gt;Ajax.BeginForm&lt;/em&gt; - we can use it now without any problems. Another important change you should notice is usage of new strongly typed helpers.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;We now should adjust the view markup to use our user control:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;div&lt;/span&gt; &lt;span style="color: red;"&gt;id&lt;/span&gt;&lt;span style="color: blue;"&gt;="dvAccountInformationFormContainer"&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt; Html.RenderPartial(&lt;span style="color: #b45f06;"&gt;"~/Views/Home/AccountInformationForm.ascx"&lt;/span&gt;, Model); &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;div&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;Next thing is&amp;nbsp;to modify&amp;nbsp;our controller actions:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;&lt;span style="color: #666666;"&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;
///&lt;/span&gt; &lt;span style="color: #38761d;"&gt;GET Home/AsynchronousForm&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: #666666;"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: #666666;"&gt;/// &amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="color: #38761d;"&gt;AsynchronousForm view&lt;/span&gt;&lt;span style="color: #666666;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;ViewResult&lt;/span&gt; AsynchronousForm()&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return&lt;/span&gt; View(&lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;AsynchronousFormViewModel&lt;/span&gt;());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #666666;"&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;
///&lt;/span&gt; &lt;span style="color: #38761d;"&gt;POST Home/AsynchronousForm&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: #666666;"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: #666666;"&gt;/// &amp;lt;param name="viewModel"&amp;gt;&lt;/span&gt;&lt;span style="color: #38761d;"&gt;The form post data&lt;/span&gt;&lt;span style="color: #666666;"&gt;&amp;lt;/param&amp;gt;&lt;br /&gt;
/// &amp;lt;param name="isAjaxRequest"&amp;gt;&lt;/span&gt;&lt;span style="color: #38761d;"&gt;Value indicating if it is an AJAX request&lt;/span&gt;&lt;span style="color: #666666;"&gt;&amp;lt;/param&amp;gt;&lt;br /&gt;
/// &amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="color: #38761d;"&gt;AsynchronousForm view or json result&lt;/span&gt;&lt;span style="color: #666666;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br /&gt;
[&lt;span style="color: #6fa8dc;"&gt;AcceptVerbs&lt;/span&gt;(&lt;span style="color: #6fa8dc;"&gt;HttpVerbs&lt;/span&gt;.Post)]&lt;br /&gt;
[&lt;span style="color: #6fa8dc;"&gt;ValidateAntiForgeryToken&lt;/span&gt;]&lt;br /&gt;
[&lt;span style="color: #6fa8dc;"&gt;IsAjaxRequest&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"isAjaxRequest"&lt;/span&gt;)]&lt;br /&gt;
&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;ActionResult&lt;/span&gt; AsynchronousForm(&lt;span style="color: #6fa8dc;"&gt;AsynchronousFormViewModel&lt;/span&gt; viewModel, &lt;span style="color: blue;"&gt;bool&lt;/span&gt; isAjaxRequest)&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (ModelState.IsValid)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;try&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_usersRepository.RegisterUser(viewModel.UserName, viewModel.Email, viewModel.Password);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;viewModel = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;AsynchronousFormViewModel&lt;/span&gt;() { UserRegistered = &lt;span style="color: blue;"&gt;true&lt;/span&gt; };&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;catch&lt;/span&gt; (&lt;span style="color: #6fa8dc;"&gt;Exception&lt;/span&gt; ex)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ModelState.AddModelError(&lt;span style="color: #b45f06;"&gt;"_FORM"&lt;/span&gt;, ex.Message);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (isAjaxRequest)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return&lt;/span&gt;&amp;nbsp;PartialView(&lt;span style="color: #b45f06;"&gt;"AccountInformationForm"&lt;/span&gt;,&amp;nbsp;viewModel);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;else&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return&lt;/span&gt; View(viewModel);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #666666;"&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;
///&lt;/span&gt; &lt;span style="color: #38761d;"&gt;Validates username&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: #666666;"&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;
/// &amp;lt;param name="UserName"&amp;gt;&lt;/span&gt;&lt;span style="color: #38761d;"&gt;The username&lt;/span&gt;&lt;span style="color: #666666;"&gt;&amp;lt;/param&amp;gt;&lt;br /&gt;
/// &amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="color: #38761d;"&gt;true or false&lt;/span&gt;&lt;span style="color: #666666;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;JsonResult&lt;/span&gt; ValidateUserName(&lt;span style="color: blue;"&gt;string&lt;/span&gt; UserName)&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return&lt;/span&gt; Json(_usersRepository.ValidateUserNameUnique(UserName), &lt;span style="color: #6fa8dc;"&gt;JsonRequestBehavior&lt;/span&gt;.AllowGet);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #666666;"&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;
///&lt;/span&gt; &lt;span style="color: #38761d;"&gt;Validates password&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: #666666;"&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;
/// &amp;lt;param name="Password"&amp;gt;&lt;/span&gt;&lt;span style="color: #38761d;"&gt;The password&lt;/span&gt;&lt;span style="color: #666666;"&gt;&amp;lt;/param&amp;gt;&lt;br /&gt;
/// &amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="color: #38761d;"&gt;true or error message&lt;/span&gt;&lt;span style="color: #666666;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;JsonResult&lt;/span&gt; ValidatePassword(&lt;span style="color: blue;"&gt;string&lt;/span&gt; Password)&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;string&lt;/span&gt; passwordInvalidMessage = _usersRepository.ValidatePassword(Password);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (&lt;span style="color: #6fa8dc;"&gt;String&lt;/span&gt;.IsNullOrEmpty(passwordInvalidMessage))&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return&lt;/span&gt; Json(&lt;span style="color: blue;"&gt;true&lt;/span&gt;, &lt;span style="color: #6fa8dc;"&gt;JsonRequestBehavior&lt;/span&gt;.AllowGet);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;else&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return&lt;/span&gt; Json(passwordInvalidMessage, &lt;span style="color: #6fa8dc;"&gt;JsonRequestBehavior&lt;/span&gt;.AllowGet);&lt;br /&gt;
}&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;Most of changes are in action responsible for handling &lt;em&gt;Post&lt;/em&gt; request - it should now return markup which will be injected in our page using script generated by &lt;em&gt;Ajax.BeginForm&lt;/em&gt;. We also had to add &lt;em&gt;JsonRequestBehavior.AllowGet&lt;/em&gt; to &lt;em&gt;JsonResult&lt;/em&gt; because of changes in ASP.NET MVC 2 (by default &lt;em&gt;JsonResult&lt;/em&gt; is allowed only for &lt;em&gt;Post&lt;/em&gt; request).&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;Now it's time for key changes. We will remove &lt;em&gt;IDataErrorInfo&lt;/em&gt; interface from &lt;em&gt;ViewModel&lt;/em&gt; class and add &lt;em&gt;DataAnnotations&lt;/em&gt;. The&amp;nbsp;problem is, that by default we have only four rules: &lt;em&gt;Required&lt;/em&gt;, &lt;em&gt;Range&lt;/em&gt;, &lt;em&gt;StringLength&lt;/em&gt; and &lt;em&gt;RegularExpression&lt;/em&gt;. In our sample we can only use &lt;em&gt;Required&lt;/em&gt; (I will also use &lt;em&gt;DisplayName&lt;/em&gt; attribute for labels) and for the&amp;nbsp;rest of rules&amp;nbsp;we have to write our own attributes.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;Let's go step by step through implementing a &lt;em&gt;DataAnnotation&lt;/em&gt; attribute for &lt;em&gt;minlength&lt;/em&gt; rule and making it work on client-side. First, we need to create an attribute delivered from &lt;em&gt;ValidationAttribute&lt;/em&gt;:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;[&lt;span style="color: #6fa8dc;"&gt;AttributeUsage&lt;/span&gt;(&lt;span style="color: #6fa8dc;"&gt;AttributeTargets&lt;/span&gt;.Property, AllowMultiple = &lt;span style="color: blue;"&gt;false&lt;/span&gt;, Inherited = &lt;span style="color: blue;"&gt;true&lt;/span&gt;)]&lt;br /&gt;
&lt;span style="color: blue;"&gt;public class&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;MinLengthAttribute&lt;/span&gt; : &lt;span style="color: #6fa8dc;"&gt;ValidationAttribute&lt;/span&gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Properties&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public int&lt;/span&gt; MinLength { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Constructor&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt; MinLengthAttribute(&lt;span style="color: blue;"&gt;int&lt;/span&gt; minLength)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MinLength = minLength;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Methods&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public override bool&lt;/span&gt; IsValid(&lt;span style="color: blue;"&gt;object&lt;/span&gt; value)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (value == &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return true;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;if&lt;/span&gt; ((value &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;String&lt;/span&gt;).Length &amp;lt; MinLength)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return false&lt;/span&gt;;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return true&lt;/span&gt;;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
}&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;The implementation is pretty straightforward and doesn't require any sophisticated comments. This is all we need to make it work on server-side, now let's make&amp;nbsp;it&amp;nbsp;work on client-side. We need to prepare a validator class (in this case it will be class delivered from &lt;em&gt;DataAnnotationsModelValidator&amp;lt;TAttribute&amp;gt;&lt;/em&gt;):&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;&lt;span style="color: blue;"&gt;public class&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;MinLengthValidator&lt;/span&gt; : &lt;span style="color: #6fa8dc;"&gt;DataAnnotationsModelValidator&lt;/span&gt;&amp;lt;&lt;span style="color: #6fa8dc;"&gt;MinLengthAttribute&lt;/span&gt;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Fields&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;int&lt;/span&gt; _minLength;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;string&lt;/span&gt; _errorMessage;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Constructor&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt; MinLengthValidator&lt;span style="color: #6fa8dc;"&gt;(ModelMetadata&lt;/span&gt; metadata, &lt;span style="color: #6fa8dc;"&gt;ControllerContext&lt;/span&gt; context, &lt;span style="color: #6fa8dc;"&gt;MinLengthAttribute&lt;/span&gt; attribute)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;: base(metadata, context, attribute) &lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_minLength = attribute.MinLength;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_errorMessage = attribute.ErrorMessage;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: #6fa8dc;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Methods&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public override&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color: #6fa8dc;"&gt;ModelClientValidationRule&lt;/span&gt;&amp;gt; GetClientValidationRules()&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;var&lt;/span&gt; validatioRule = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;ModelClientValidationRule&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ErrorMessage = _errorMessage,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ValidationType = &lt;span style="color: #b45f06;"&gt;"minlength"&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;validatioRule.ValidationParameters.Add(&lt;span style="color: #b45f06;"&gt;"length"&lt;/span&gt;, _minLength);&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return new&lt;/span&gt;[] { validatioRule };&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;#endregion&lt;/span&gt;&lt;br /&gt;
}&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;The most important method here is &lt;em&gt;GetCleintValidationRules&lt;/em&gt;, it will be used for generating metadata which will be injected into the client script. Now, we have to register the validator with ASP.NET MVC 2 engine (preferably in &lt;em&gt;Global.asax&lt;/em&gt;:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;&lt;span style="color: #6fa8dc;"&gt;DataAnnotationsModelValidatorProvider&lt;/span&gt;.RegisterAdapter(&lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #6fa8dc;"&gt;MinLengthAttribute&lt;/span&gt;), &lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #6fa8dc;"&gt;MinLengthValidator&lt;/span&gt;));&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;We also have to modify &lt;em&gt;MicrosoftMvcJQueryValidation.js&lt;/em&gt; in two places. First, we should add following function:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;&lt;span style="color: blue;"&gt;function&lt;/span&gt; __MVC_ApplyValidator_MinLength(object, length) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;object[&lt;span style="color: #b45f06;"&gt;"minlength"&lt;/span&gt;] = length;&lt;br /&gt;
}&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;Then modify &lt;em&gt;__MVC_CreateRulesForField&lt;/em&gt; function by extending &lt;em&gt;switch&lt;/em&gt; statement inside of it:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;&lt;span style="color: blue;"&gt;switch&lt;/span&gt; (thisRule.ValidationType) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;...&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: #b45f06;"&gt;"minlength"&lt;/span&gt;:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;__MVC_ApplyValidator_MinLength(rulesObj,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;thisRule.ValidationParameters[&lt;span style="color: #b45f06;"&gt;"length"&lt;/span&gt;]);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;break;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;...&lt;br /&gt;
}&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;Following those steps we can implement attributes and validators for all&amp;nbsp;needed rules. You can find &lt;a href="https://tpeczek.svn.codeplex.com/svn/trunk/Lib.Web.Mvc/Lib.Web.Mvc/JQuery/Validation/"&gt;here&lt;/a&gt;&amp;nbsp;final source code of those used in sample.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;You should take special interest in &lt;em&gt;EqualToAttribute&lt;/em&gt;. ASP.NET MVC 2 has been built for .Net Framework 3.5, because of that there is no access to context in &lt;em&gt;ValidatorAttribute&lt;/em&gt;. This is why cross properties check can't be done on property level, but has to be done on class level. On the other hand, class level attributes doesn't generate client-side validation. This is why this attribute must be placed on class and property to make it work on client and server side (nasty workaround but it is necessary).&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;When all the &lt;em&gt;DataAnnotations&lt;/em&gt; attributes are finished, we can finally change our &lt;em&gt;ViewModel&lt;/em&gt;:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;[&lt;span style="color: #6fa8dc;"&gt;EqualTo&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"Password"&lt;/span&gt;, &lt;span style="color: #b45f06;"&gt;"ConfirmPassword"&lt;/span&gt;, &lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #6fa8dc;"&gt;AsynchronousFormViewModel&lt;/span&gt;), ErrorMessage = &lt;span style="color: #b45f06;"&gt;"Confirm password does not match password"&lt;/span&gt;)]&lt;br /&gt;
&lt;span style="color: blue;"&gt;public class&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;AsynchronousFormViewModel&lt;/span&gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Properties&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;DisplayName&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"Username:"&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;Required&lt;/span&gt;(ErrorMessage = &lt;span style="color: #b45f06;"&gt;"Please enter username"&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;MinLength&lt;/span&gt;(5, ErrorMessage = &lt;span style="color: #b45f06;"&gt;"Please enter username with at least 5 characters"&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;Remote&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"ValidateUserName"&lt;/span&gt;, &lt;span style="color: #b45f06;"&gt;"Home"&lt;/span&gt;, &lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #6fa8dc;"&gt;DummyUsersRepository&lt;/span&gt;), &lt;span style="color: #b45f06;"&gt;"ValidateUserNameUnique"&lt;/span&gt;, ErrorMessage = &lt;span style="color: #b45f06;"&gt;"Username is already in use"&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public string&lt;/span&gt; UserName { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;DisplayName&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"Email:"&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;Required&lt;/span&gt;(ErrorMessage = &lt;span style="color: #b45f06;"&gt;"Please enter email address"&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;Email&lt;/span&gt;(ErrorMessage = &lt;span style="color: #b45f06;"&gt;"Please enter valid email address"&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public string&lt;/span&gt; Email { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;DisplayName&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"Password:"&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;Required&lt;/span&gt;(ErrorMessage = &lt;span style="color: #b45f06;"&gt;"Please enter password"&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;Remote&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"ValidatePassword"&lt;/span&gt;, &lt;span style="color: #b45f06;"&gt;"Home"&lt;/span&gt;, &lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #6fa8dc;"&gt;DummyUsersRepository&lt;/span&gt;), &lt;span style="color: #b45f06;"&gt;"ValidatePassword"&lt;/span&gt;, ErrorMessage = &lt;span style="color: blue;"&gt;null&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public string&lt;/span&gt; Password { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;DisplayName&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"Confirm password:"&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;Required&lt;/span&gt;(ErrorMessage = &lt;span style="color: #b45f06;"&gt;"Please repeat password"&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;[&lt;span style="color: #6fa8dc;"&gt;EqualTo&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"Password"&lt;/span&gt;, &lt;span style="color: #b45f06;"&gt;"ConfirmPassword"&lt;/span&gt;, &lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #6fa8dc;"&gt;AsynchronousFormViewModel&lt;/span&gt;), ErrorMessage = &lt;span style="color: #b45f06;"&gt;"Confirm password does not match password"&lt;/span&gt;)]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public string&lt;/span&gt; ConfirmPassword { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public bool&lt;/span&gt; UserRegistered { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
}&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;The sample is finished. We have achieved the same functionality, but the code fallows &lt;em&gt;DRY&lt;/em&gt; principle now. You can download complete &lt;a href="https://tpeczek.svn.codeplex.com/svn/trunk/MVC/AsynchronousFormExamplev2/"&gt;source code&lt;/a&gt; from Codeplex.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=AmzZvG2toao:BJe-T22JJXI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=AmzZvG2toao:BJe-T22JJXI:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/AmzZvG2toao" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/04/unobtrusive-asynchronous-form-in-aspnet.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><thr:total>9</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7365737872932202828.post-8545237824672102374</guid><pubDate>Mon, 08 Mar 2010 15:57:00 +0000</pubDate><atom:updated>2010-03-08T16:57:25.034+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">file upload</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><title>Rich file upload experience in ASP.NET MVC - part I</title><description>&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;As you can figure out by the title, I'm going to write few posts about creating rich file upload experience in ASP.NET MVC. In my&amp;nbsp;approach I will try to keep away from &lt;em&gt;Flash&lt;/em&gt; (which is really often used for such scenarios) and stick only with jQuery.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;So first, you should know how to handle file upload in ASP.NET MVC. The client side is simple, you need a &lt;em&gt;form&lt;/em&gt; with &lt;em&gt;enctype = "multipart/form-data"&lt;/em&gt; and an &lt;em&gt;input&lt;/em&gt; of type &lt;em&gt;file&lt;/em&gt; inside of it. On server side you can found files posted by user in &lt;em&gt;Request.Files&lt;/em&gt; collection, where every file is represented by &lt;em&gt;HttpPostedFileBase&lt;/em&gt; object.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;Now, when we know the basics, we can start writting some code. First we will write some wrappers, which will allow us to keep our code unit testable:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;&lt;span style="color: blue;"&gt;public interface&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;IHttpPostedFileBase&lt;/span&gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Properties&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;int&lt;/span&gt; ContentLength { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;string&lt;/span&gt; ContentType { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;string&lt;/span&gt; FileName { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: #6fa8dc;"&gt;Stream&lt;/span&gt; InputStream { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Methods&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;void&lt;/span&gt; SaveAs(&lt;span style="color: blue;"&gt;string&lt;/span&gt; filename);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: blue;"&gt;public class&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;HttpPostedFileBaseWrapper&lt;/span&gt;: &lt;span style="color: #6fa8dc;"&gt;IHttpPostedFileBase&lt;/span&gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Fields&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;HttpPostedFileBase&lt;/span&gt; _postedFileBase;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; IHttpPostedFile Members&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public int&lt;/span&gt; ContentLength&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; _postedFileBase.ContentLength; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public string&lt;/span&gt; ContentType&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; _postedFileBase.ContentType; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public string&lt;/span&gt; FileName&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; _postedFileBase.FileName; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt; System.IO.&lt;span style="color: #6fa8dc;"&gt;Stream&lt;/span&gt; InputStream&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; _postedFileBase.InputStream; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public void&lt;/span&gt; SaveAs(&lt;span style="color: blue;"&gt;string&lt;/span&gt; filename)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_postedFileBase.SaveAs(filename);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Constructor&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt; HttpPostedFileBaseWrapper(&lt;span style="color: #6fa8dc;"&gt;HttpPostedFileBase&lt;/span&gt; postedFileBase)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_postedFileBase = postedFileBase;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
}&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;So now, instead of &lt;em&gt;HttpPostedFileBase&lt;/em&gt; object (which can't be created while unit testing), we have &lt;em&gt;IHttpPostedFileBase&lt;/em&gt; which will allow us to provide different implementation when necessary.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;Next&amp;nbsp;we should take care of accessing &lt;em&gt;Request.Files&lt;/em&gt; collection (remember, if you want to keep your controller unit testable, avoid accessing &lt;em&gt;Request&lt;/em&gt; inside action method). We will prepare a class which will contain a collection of &lt;em&gt;IHttpPostedFileBase&lt;/em&gt; and a model binder for this class:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;[&lt;span style="color: #6fa8dc;"&gt;ModelBinder&lt;/span&gt;(&lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #6fa8dc;"&gt;HttpPostedFilesModelBinder&lt;/span&gt;))]&lt;br /&gt;
&lt;span style="color: blue;"&gt;public class&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;HttpPostedFiles&lt;/span&gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Fields&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #6fa8dc;"&gt;IHttpPostedFileBase&lt;/span&gt;&amp;gt; _postedFiles;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Properties&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #6fa8dc;"&gt;IHttpPostedFileBase&lt;/span&gt;&amp;gt; PostedFiles&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; _postedFiles; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Constructor&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt; HttpPostedFiles()&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_postedFiles = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #6fa8dc;"&gt;IHttpPostedFileBase&lt;/span&gt;&amp;gt;();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: blue;"&gt;public class&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;HttpPostedFilesModelBinder&lt;/span&gt; : &lt;span style="color: #6fa8dc;"&gt;IModelBinder&lt;/span&gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; IModelBinder Members&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public object&lt;/span&gt; BindModel(&lt;span style="color: #6fa8dc;"&gt;ControllerContext&lt;/span&gt; controllerContext, &lt;span style="color: #6fa8dc;"&gt;ModelBindingContext&lt;/span&gt; bindingContext)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (controllerContext == &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;throw new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"controllerContext"&lt;/span&gt;);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (bindingContext == &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;throw new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"bindingContext"&lt;/span&gt;);&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #6fa8dc;"&gt;HttpPostedFiles&lt;/span&gt; postedFiles = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;HttpPostedFiles&lt;/span&gt;();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color: blue;"&gt;string&lt;/span&gt; postedInputName &lt;span style="color: blue;"&gt;in&lt;/span&gt; controllerContext.HttpContext.Request.Files)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (controllerContext.HttpContext.Request.Files[postedInputName] != &lt;span style="color: blue;"&gt;null&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;amp;&amp;amp; controllerContext.HttpContext.Request.Files[postedInputName].ContentLength &amp;gt; 0)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;postedFiles.PostedFiles.Add(&lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;HttpPostedFileBaseWrapper&lt;/span&gt;(controllerContext.HttpContext.Request.Files[postedInputName]));&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return&lt;/span&gt; postedFiles;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
}&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;The issue of accessing &lt;em&gt;Request.Files&lt;/em&gt; is solved.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;In my sample solution I'm going to keep user uploads in Session, so I have to write two more classes which will take care of binding those for the action method:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;[&lt;span style="color: #6fa8dc;"&gt;ModelBinder&lt;/span&gt;(&lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #6fa8dc;"&gt;SessionUploadedFilesModelBinder&lt;/span&gt;))]&lt;br /&gt;
&lt;span style="color: blue;"&gt;public class&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;SessionUploadedFiles&lt;/span&gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Fields&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #6fa8dc;"&gt;FileInfo&lt;/span&gt;&amp;gt; _uploadedFiles;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Properties&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #6fa8dc;"&gt;FileInfo&lt;/span&gt;&amp;gt; UploadedFiles&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; _uploadedFiles; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; Constructor&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt; SessionUploadedFiles()&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_uploadedFiles = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #6fa8dc;"&gt;FileInfo&lt;/span&gt;&amp;gt;();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: blue;"&gt;public class&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;SessionUploadedFilesModelBinder&lt;/span&gt; : &lt;span style="color: #6fa8dc;"&gt;IModelBinder&lt;/span&gt;&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#region&lt;/span&gt; IModelBinder Members&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public object&lt;/span&gt; BindModel(&lt;span style="color: #6fa8dc;"&gt;ControllerContext&lt;/span&gt; controllerContext, &lt;span style="color: #6fa8dc;"&gt;ModelBindingContext&lt;/span&gt; bindingContext)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (controllerContext == &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;throw new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"controllerContext"&lt;/span&gt;);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (bindingContext == &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;throw new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;ArgumentNullException&lt;/span&gt;(&lt;span style="color: #b45f06;"&gt;"bindingContext"&lt;/span&gt;);&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #6fa8dc;"&gt;SessionUploadedFiles&lt;/span&gt; uploadedFiles = (&lt;span style="color: #6fa8dc;"&gt;SessionUploadedFiles&lt;/span&gt;)controllerContext.HttpContext.Session[&lt;span style="color: #b45f06;"&gt;"UPLOADED_FILES"&lt;/span&gt;];&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (uploadedFiles == &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;uploadedFiles = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;SessionUploadedFiles&lt;/span&gt;();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;controllerContext.HttpContext.Session[&lt;span style="color: #b45f06;"&gt;"UPLOADED_FILES"&lt;/span&gt;] = uploadedFiles;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return&lt;/span&gt; uploadedFiles;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;
}&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;After that, we can write our action methods:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;ActionResult&lt;/span&gt; FileUpload(&lt;span style="color: #6fa8dc;"&gt;SessionUploadedFiles&lt;/span&gt; uploadedFiles)&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return&lt;/span&gt; View(uploadedFiles);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[&lt;span style="color: #6fa8dc;"&gt;AcceptVerbs&lt;/span&gt;(&lt;span style="color: #6fa8dc;"&gt;HttpVerbs&lt;/span&gt;.Post)]&lt;br /&gt;
&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;ActionResult&lt;/span&gt; FileUpload(&lt;span style="color: #6fa8dc;"&gt;SessionUploadedFiles&lt;/span&gt; uploadedFiles, &lt;span style="color: #6fa8dc;"&gt;HttpPostedFiles&lt;/span&gt; postedFiles)&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;string&lt;/span&gt; uploadsPath = &lt;span style="color: #6fa8dc;"&gt;Path&lt;/span&gt;.Combine(&lt;span style="color: #6fa8dc;"&gt;AppDomain&lt;/span&gt;.CurrentDomain.BaseDirectory, &lt;span style="color: #b45f06;"&gt;"Uploads"&lt;/span&gt;);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (!&lt;span style="color: #6fa8dc;"&gt;Directory&lt;/span&gt;.Exists(uploadsPath))&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #6fa8dc;"&gt;Directory&lt;/span&gt;.CreateDirectory(uploadsPath);&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color: #6fa8dc;"&gt;IHttpPostedFileBase&lt;/span&gt; postedFile &lt;span style="color: blue;"&gt;in&lt;/span&gt; postedFiles.PostedFiles)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;string&lt;/span&gt; postedFilePath = &lt;span style="color: #6fa8dc;"&gt;Path&lt;/span&gt;.Combine(uploadsPath, &lt;span style="color: #6fa8dc;"&gt;Path&lt;/span&gt;.GetFileName(postedFile.FileName));&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;postedFile.SaveAs(postedFilePath);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;uploadedFiles.UploadedFiles.Add(&lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #6fa8dc;"&gt;FileInfo&lt;/span&gt;(postedFilePath));&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;return&lt;/span&gt; View(uploadedFiles);&lt;br /&gt;
}&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;Finally, we can write our view markup (it will be strong typed View for &lt;em&gt;SessionUploadedFiles&lt;/em&gt; class):&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;ul&lt;/span&gt; &lt;span style="color: red;"&gt;class&lt;/span&gt;&lt;span style="color: blue;"&gt;="uploaded-files-list"&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (System.IO.&lt;span style="color: #6fa8dc;"&gt;FileInfo&lt;/span&gt; file &lt;span style="color: blue;"&gt;in&lt;/span&gt; Model.UploadedFiles) { &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;li&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;img&lt;/span&gt; &lt;span style="color: red;"&gt;src&lt;/span&gt;&lt;span style="color: blue;"&gt;="&lt;/span&gt;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Url.Content("~/HttpHandlers/SystemIconsHandler.ashx?type=file&amp;amp;size=small&amp;amp;ext=" + file.Extension)&lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;"&lt;/span&gt; &lt;span style="color: red;"&gt;alt&lt;/span&gt;&lt;span style="color: blue;"&gt;="&lt;/span&gt;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; file.Extension&lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;" /&amp;gt;&lt;/span&gt; &lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; Html.Encode(file.Name)&lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt; &lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt; file.Length.ToString() + &lt;span style="color: #b45f06;"&gt;" B"&lt;/span&gt;&lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;li&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;ul&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color: blue;"&gt;using&lt;/span&gt; (Html.BeginForm(&lt;span style="color: #b45f06;"&gt;"FileUpload"&lt;/span&gt;, &lt;span style="color: #b45f06;"&gt;"Home"&lt;/span&gt;, &lt;span style="color: #6fa8dc;"&gt;FormMethod&lt;/span&gt;.Post, &lt;span style="color: blue;"&gt;new&lt;/span&gt; { name = &lt;span style="color: #b45f06;"&gt;"frmUpload"&lt;/span&gt;, enctype = &lt;span style="color: #b45f06;"&gt;"multipart/form-data"&lt;/span&gt; })) { &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;input&lt;/span&gt; &lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;="file"&lt;/span&gt; &lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;="fiUpload"&lt;/span&gt; &lt;span style="color: red;"&gt;id&lt;/span&gt;&lt;span style="color: blue;"&gt;="fiUpload"&lt;/span&gt; &lt;span style="color: blue;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #b45f06;"&gt;input&lt;/span&gt; &lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;="submit"&lt;/span&gt; &lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;="btnUpload"&lt;/span&gt; &lt;span style="color: red;"&gt;id&lt;/span&gt;&lt;span style="color: blue;"&gt;="btnUpload"&lt;/span&gt; &lt;span style="color: red;"&gt;value&lt;/span&gt;&lt;span style="color: blue;"&gt;="Upload next file" /&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: yellow;"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background-color: yellow;"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;Our sample looks like this (I'm using &lt;a href="http://tpeczek.blogspot.com/2009/10/simple-systemiconshandler-for-aspnet.html"&gt;SystemIconsHandler&lt;/a&gt; for displaying icons):&lt;/span&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_c2mfEqrjR68/S47Uwvhq-gI/AAAAAAAAACY/lWDl9iXF9aQ/s1600-h/FileUpload.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" kt="true" src="http://1.bp.blogspot.com/_c2mfEqrjR68/S47Uwvhq-gI/AAAAAAAAACY/lWDl9iXF9aQ/s320/FileUpload.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;"&gt;It's hard to call it a rich user experience yet, you should rather treat it like a base, which will be extended in the&amp;nbsp;fallowing parts.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=UYawzLJ6TO8:KtiP2wpTKyY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?a=UYawzLJ6TO8:KtiP2wpTKyY:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/YetAnotherDeveloperBlog?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/YetAnotherDeveloperBlog/~4/UYawzLJ6TO8" height="1" width="1"/&gt;</description><link>http://tpeczek.blogspot.com/2010/03/rich-file-upload-experience-in-aspnet.html</link><author>noreply@blogger.com (Tomasz Pęczek)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_c2mfEqrjR68/S47Uwvhq-gI/AAAAAAAAACY/lWDl9iXF9aQ/s72-c/FileUpload.jpg" height="72" width="72" /><thr:total>4</thr:total></item></channel></rss>
