Monday 13 February 2012

Upgrade ASP.NET MVC 2 (Net 3.5) to MVC 3 (Net 4.0)

There are a few blog posts on this topic, but I found most of them don't fit all scenarios. Indeed this post is no different. Put together they might rebuild the world, who knows. Anyway, these
are the steps I went through to implement my upgrade.

Step 1: Start Visual Studio 2010 and run the Solution (.sln) file. Follow the steps to perform the upgrade. Change the target Framework version from 3.5 to 4.0 for all projects in the solution.

Step 2: Remove all references to framework 3.5 assemblies in the web.config file in the ConfigSections. i.e. the following;

<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
<sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere" />
<section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" /> >
<section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
</sectionGroup>
</sectionGroup>
</sectionGroup>

This will probably do for those who want to upgrade to .Net 4.0 without the upgrade to MVC 3. If MVC 3 is the preferred flavour, continue.

Step 3: Download and Install ASP.NET MVC 3.

Step 4: If you intend to use the new Razor View engine like I do, then add the following to the your web.config ConfigSections;

<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>

Step 5: On the official MVC website there's a white paper on how to go about the upgrade, only problem is I don't need most of it so I cherry picked what I wanted from this and other posts.

Step 6: Replace all occurences of System.Web.Mvc in the web project config files (Web.config) with the MVC 3 version.

i.e. Replace

System.Web.Mvc, Version=2.0.0.0
with

System.Web.Mvc, Version=3.0.0.0
e.g.

<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>

Step 7: For each project in the solution Add/Replace references to the following MVC 3 dlls;

System.Web.Helpers.dll
System.Web.Mvc.dll
System.Web.Razor.dll
System.Web.Routing.dll
System.Web.WebPages.Deployment.dll
System.Web.WebPages.dll
System.Web.WebPages.Razor.dll

These are located in the following folders;

%ProgramFiles%\ Microsoft ASP.NET\ASP.NET MVC 3\Assemblies
%ProgramFiles%\ Microsoft ASP.NET\ASP.NET Web Pages\v1.0\Assemblies

Step 8: Last but not least, we want the Razor View to be an option when we use the "Add View" dialogue. As per the white paper, unload the web projects in the solution and replace the GUID {F85E285D-A4E0-4152-9332-AB1D724D3325} with {E53F8FEA-EAE0-44A6-8774-FFD645390401} and reload the project.

Step 9: Go on and do your thing.

Wednesday 8 February 2012

Extending Backbone.js view using custom JavaScript namespacing

Backbone.js is an open source class library that enables an efficient client-side MVC implementation. Backbone shines if the requirement is to maintain a large collection of data on the client-side without the unnecessary round trips to the server.

I've been working on an ASP.NET MVC 3 project that involves quite a number of pages with similar look and feel. So instead of building every page from the ground up, we decided to developer a vanilla page and use it as a template for all other pages. Anyway, to encourage a reuse of the generic JavaScript file we'd come up with we split the Backbone views into separate files (ala UserControls) so we would reuse them in any other project.

We decided on a Namespacing strategy that would reduce tendency for method name collision.

To wrap a JavaScript class in a namespace;

Regedit.View = function(){
//Write your private functions here
//e.g. function myprivates() {}
return {
//Write your public functions here
//e.g mypublic: function(){}
};
}();
Note this will work only if you already have an existing "Regedit" namespaces already defined and referenced by this file. With this on place we could extend/inherit a Backbone view module like so;

Regedit.View = function () {
return {
extend: function (classProps) {
return Backbone.View.extend({
el: $("#someElement"),
initialize: function (customCollection) {
_.bindAll(this, "render"); //Enable This keyword in render method
//pass the view context on to the derived the derived class
//This will enable the derived class use the "this" keyword to refer this view
if(classProps.initialize != undefined){
classProps.initialize(this);
}
//this.models = customCollection;
},
template: $("#template"),
events: {
"change #someEvent": "SomeEventHandler"
},
SomeEventHandler: function(){
//this.contructor.someDerivedClassMethod();
}
}, classProps);
}
};
} ();

With our custom view in place, we can create a view using our custom module;

var newView = Regedit.View.extend({
//Custom view properties here
initialize: function(viewContext){ //this will be called from the base class
_.bind(viewContext, this.derivedClassMethod)
},
derivedClassMethod: function(){
this.someBaseClassMethod() //The "this" keyword will refer to the current view context
}
});

The class utilises the underscore.js library's _.extend method to extend/inherit a backbone view, but the same technique can be employed to extend a backbone model or collection as well.

This post is not a tutorial for Backbone.js. To learn more about or download Backbone.js, please visit the backbone.js website.

Happy coding.

Saturday 4 February 2012

GroupBy multiple columns using Dynamic LINQ

It can be quite useful at times to have the capability to identify duplicate objects based on custom rules (or in my case based on user input). Since this input is not known at design time, I started looking for a Dynamic Linq functionality that would take a collection of objects, a list of columns and dynamically group by the list of columns at runtime.

The closest I came to what I was looking for is a listing on Scott Gu's blog. There's a link in the blog to download the DynamicLibrary.

Now the following function can be authored to utilise the "GroupBy" extension method on the downloaded class to perform the Dlinq operation.

var query = customerData.AsQueryable().GroupBy("new ("Title, FirstName, LastName")", "it", null);
var groupedCustomerData = (from IEnumerable<Customer> groupedData in
query select groupedData.FirstOrDefault()).ToList();

return groupedCustomerData;


The "it" keyword is used as the KeySelector parameter if the requirement is to return the whole customer object in the group. The code above should group the customer data collection by the Title, FirstName and the LastName attributes.