InvalidCastException after upgrading from ASP.NET MVC 3 to ASP.NET MVC 4

I have recently upgraded a MVC 3 application to MVC 4 but along the way en-counted some issues around upgrading references in the project.

Specially, I got this error.

1
2
3
4
5
6
7
8
9
System.InvalidCastException was unhandled by user code
Message=[A]System.Web.WebPages.Razor.Configuration.HostSection cannot be cast
to [B]System.Web.WebPages.Razor.Configuration.HostSection. Type A originates
from 'System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35' in the context 'Default' at location
'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.WebPages.Razor\v4.0_1.0.0.0__31bf3856ad364e35\System.Web.WebPages.Razor.dll'.
Type B originates from 'System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
in the context 'Default' at location 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.WebPages.Razor\v4.0_2.0.0.0__31bf3856ad364e35\System.Web.WebPages.Razor.dll'.
Source=System.Web.WebPages.Razor

Sources on the interweb say that you should change the webpages element back to 1.0.0.0 from 2.0.0.0 in your web config:

1
2
3
<appSettings>
  <add key="webpages:Version" value="1.0.0.0"/>
</appSettings>

but this seems a bit strange having to specify a old version to use the new version of System.Mvc.WebPages?

I believe the better solution is to add a binding redirect to tell any reference that has been using System.Mvc.WebPages 1.0.0.0 to use 2.0.0.0.

the following goes into your web.config

1
2
3
4
5
6
7
8
9
10
 <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
   
      <dependentAssembly>
          <assemblyIdentity name="System.Web.WebPages.Razor"
              publicKeyToken="31bf3856ad364e35" />
          <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

Upgrading MVC Project 2 to 4 and open it in VS 2012

I have an old MVC 2 project that works fine in VS 2010. However, if you try and open the project in VS 2012 you will get a “incompatible” error and left with no way to upgrade the project to VS 2012.

Here are some pointers to get it working (this is how I got it working for myself).

In VS2010, upgrade your MVC project to version 4. You need to follow the upgrade steps for upgrading to MVC 2 – 3 first.

http://www.asp.net/whitepapers/mvc3-release-notes#upgrading

Secondly, upgrade from MVC 3 to 4 using the following link.

http://www.asp.net/whitepapers/mvc4-release-notes#_Toc303253806

Once you have done this, you need to edit the project file of the working web application (i.e csproj). Firstly, open the solution in VS2012, the web project will not work but you can edit the project file directly in the IDE.

Make sure that you add the MVC 4 ProjectTypes GUID ({E3E379DF-F4C6-4180-9B81-6769533ABE47}) and remove the old MVC ProjectTypes GUID ({F85E285D-A4E0-4152-9332-AB1D724D3325}).

Here is a list of available GUIDS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Windows (C#) {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
Windows (VB.NET) {F184B08F-C81C-45F6-A57F-5ABD9991F28F}
Windows (Visual C++) {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}
Web Application {349C5851-65DF-11DA-9384-00065B846F21}
Web Site {E24C65DC-7377-472B-9ABA-BC803B73C61A}
WCF {3D9AD99F-2412-4246-B90B-4EAA41C64699}
WPF {60DC8134-EBA5-43B8-BCC9-BB4BC16C2548}
XNA (Windows) {6D335F3A-9D43-41b4-9D22-F6F17C4BE596}
XNA (XBox) {2DF5C3F4-5A5F-47a9-8E94-23B4456F55E2}
XNA (Zune) {D399B71A-8929-442a-A9AC-8BEC78BB2433}
Silverlight {A1591282-1198-4647-A2B1-27E5FF5F6F3B}
ASP.NET MVC {F85E285D-A4E0-4152-9332-AB1D724D3325}
ASP.NET MVC 4 {E3E379DF-F4C6-4180-9B81-6769533ABE47}
Test {3AC096D0-A1C2-E12C-1390-A8335801FDAB}
Solution Folder {2150E333-8FDC-42A3-9474-1A3956D46DE8}

http://stackoverflow.com/questions/2911565/what-is-the-significance-of-projecttypeguids-tag-in-the-visual-studio-project-fi

From here you reload the project (after you save the project file) and a way you go.

405 Method Not Allowed using ASP.NET Web API

I have been using the ASP.NET Web API recently on a project and this has been working well together with Backbone.js as the front end framework. I have been using PUT for updating the model and POST for adding to the model.

Everything is going well until I deployed the application on a production server. I got the error when trying to perform a PUT request to the server from the front-end. The error was “405 Method not allowed”.

The reason for this is two parts; one the production server has WebDav installed and this has caused conflicts with ASP.NET Web API and two by default the handler was not allowing the PUT verb.

The solution was to remove the WebDav handler and WebDav module from web.config and change the ExtensionlessUrl handler verb attribute.

1
2
3
4
5
6
7
8
9
10
11
12
<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="WebDAVModule" />
    </modules>
    <handlers>
      <remove name="WebDAV" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT" type="System.Web.Handlers.TransferRequestHandler" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
   
  </system.webServer>

When to use TempData in ASP.NET MVC

The problem

I came across this problem where I had a basic list of items and for each if these items I wanted to add a delete action on my controller. I wanted to add some error checking around the delete action so if someone attempted to modify the URL and enter a incorrect parameter into my controller, I wanted to redirect back to the previous controller and notify the user of this mistake. Take this example. I have a Product Controller and the Index Action and View lists all of the products. I have a delete action on the Product Controller which checks if the productId parameter is valid and then removes the product and redirects to the Index action using the RedirectToAction method.

The solution

When validating the productId, if its NOT valid simply add a new key/value to the TempData object and call the RedirectToAction method. TempData stores data for short periods of time for the current and next HTTP request. In your index view, you can check to see if your key/value pair exists and display a error message. If you refresh the page, you will notice the data from the TempData will be gone. Remember to use RedirectToAction where possible as this is more friendly with Unit Testing rather than using the HttpResponse redirect method.

This reference illustrates a good understanding between TempData, ViewBag and ViewData.

http://rachelappel.com/when-to-use-viewbag-viewdata-or-tempdata-in-asp.net-mvc-3-applications

Areas and ASP.NET MVC Routes Tip

Lets say that you have several areas define in your ASP.NET MVC solution. You find that when you run your application you get the following error “Multiple types were found that match the controller named ‘Home’.”. This is because ASP.NET MVC finds all the routing definitions (i.e in each area.cs file or the global.asax) and sees conflicts with duplicate controller names.
Simple solution is to associate the namespace with the routes you are registering. Take the example below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// global.asax route
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new string[] { "MyApplication.Controllers" } // Controller Namespace
);
?
// Area Registration Route
context.MapRoute(
MyArea_default,
"MyArea/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new string[] { "MyApplication.Areas.MyArea.Controllers" }
);

Credit to Steve Testa, Thanks!.

Elmah and MVC 3 Error Handling

I came into an issue where I have Elmah configured on a ASP.NET MVC 3 website. I notice that the errors were not getting logged or emailed as per my configuration settings in web.config.
I found that MVC3 Error Handling was handling all the errors before Elmah could handle the error and report it correctly.

This link was very helpful:

http://thecodersperspective.posterous.com/how-to-get-elmah-and-mvc3-error-handling-to-p

Also when using Elmah on a production environment, its a good idea to lock down the permissions for the elmah.axd handler so only users in a particular role have access to this file. (Assuming that your website is using forms authentication and role provider)

1
2
3
4
5
6
7
8
 <location path="elmah.axd">
    <system.web>
      <authorization>
        <allow roles="Administrators" />
        <deny users="*" />
      </authorization>
    </system.web>
  </location>

And also make sure that this setting is set to false so its not available to remote users.

1
<security allowRemoteAccess="0" />

handling multiple submit buttons in one form (asp.net webforms)

I came across an issue where I had the following setup with an asp.net website:

  1. I had a master page with one main form element
  2. I had a submit button in the master page which acts as a search button across the website
  3. I had a login page that also has a submit button

Naturally when the user presses the enter key, it naturally takes the first submit button on the webpage as being the default submit button.   Therefore when a user enters their credentials on the login page, they will always be taken to the search page which is defined by the input button on the master page.

I used jQuery to help solve this issue, you need to do two important things:

1) You need to set a default selector on the input button you want to submit, i.e on the login button I put:

1
 <input class="buttondefault" name="myButton" type="submit" />

 

2) Use the following code (Note this code can easily be refactored to be more efficient):

1
2
3
4
5
6
7
8
9
10
11
12
13
$("form input").keypress(function (e) {
if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
//if the search has text then submit that button first
if ($('.buttondefault').length > 0) {
$('.buttondefault').click();
return false;
}
$('#myMasterButtonClass input[type=submit]').click();
return false;
} else {
return true;
}
});

Compiler Error Message: CS1973

I came across this error when I was trying to use the @Render method to render a view while passing through a object that will act as the model for that view.

Compiler Error Message: CS1973: ‘System.Web.Mvc.HtmlHelper’ has no applicable method named ‘Render’ but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.

The issue was that the compiler could not choose the correct method because my model was “dynamic”.

The correct syntax is:

1
@Html.Partial("_MyList",(MyClass)myObject)

Disabling Request Validation with ASP.NET MVC

Sometimes when dealing with POSTS and form data, you need to disable Request Validation to allow HTML/scripting data into your methods.   Traditionally with Web Forms you use <%@ Page ValidateRequest=”false” %> which turns off Request Validation, just be aware that this doesn’t work with ASP.NET MVC.

You apply the [ValidateInput] attribute to the controller action in order to make this happen.

1
2
3
4
5
6
7
8
9
[ValidateInput(false)]

[AcceptVerbs(HttpVerbs.Post)]

public ActionResult Create([Bind(Exclude="Id")]Product productToCreate)

{

}

A CMS that integrates into ASP.NET MVC

Here is a open source CMS called N2 that provides a CMS framework to build web applications on using the ASP.NET MVC Model.   Its a very basic CMS, but it provides all the core functionality including Pages, Articles and a .NET Permissions Model (it also has some add ons and allows developers to contribute their own add ons).   They have lots of documentation and useful examples on how to work the CMS with MVC.   Very cool stuff!

References:

http://n2cms.com