find a location for property in a new city

Thursday 27 May 2010

MVC2 deploy - Could not load file or assembly 'System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies.

A new MVC 2 project worked on my local machine but when it was deployed to the test server it gave the error 'Could not load file or assembly 'System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies.' I have the full Visual Studio 2010 installed on my local machine but just the .NET 4 framework installed on the test servers. It seems the MVC assemblies do not come with .NET 4 framework itself so how to make MVC 2 work on the test servers?

Update This was written for difficulties with deploying an MVC 2 app. I have written a new blog post about deploying an ASP.NET MVC 3 web application to keep you up to date with the new technologies.

When I installed Visual Studio 2010 on my local machine it came with all the fruit included (.NET4 framework, MVC2 etc) so the System.Web.Mvc.dll can be found in my machine's GAC (C:\Windows\assembly). However, since there is no need to bloat the web servers only the plain old .NET4 framework has been installed on the test servers. This does NOT include the MVC assembly and that is why it cannot be found by the web application.

You need this assembly to be on your web servers that you are deploying to but you want to avoid having to copy them into the GAC manually and doing all that gacutil mess or maybe you don't have access to your servers if they are hosted by godaddy or something.

Solution

You need to make the System.Web.Mvc assembly bin deployable... okay that doesn't sound easy but here is how to do it for the necessary MVC references:

Simply right click the reference and select 'Properties':

Then change 'Copy Local' to 'True':

Note

If your server has .NET 3.5 sp1 installed the new(ish) assemblies System.Web.Routing and System.Web.Abstractions will already be in the GAC. If you had previously deployed an MVC 1 application to a .NET 3.5 server you may remember having to deploy the other two assemblies too. Since MVC2 requires at least .NET 3.5 sp1 you will not need to worry about these assemblies, just System.Web.Mvc.

Update

There is an easier way to do this if you are using Visual Studio 2010 Service Pack 1 and using Web Deploy as your publish action when publishing. You can add deployable dependencies to your ASP.NET MVC project that will choose the necessary assemblies for you. Even easier!

Follow britishdev on Twitter

Wednesday 26 May 2010

How to add an ASP.NET MVC 2 project to an existing ASP.NET Web forms application

In this 'how to' I will demonstrate how to integrate an ASP.NET MVC 2 project to an ASP.NET WebForms application that already exists. There are many weird ungoogleable issues and extra tips that haven't been covered elsewhere. I hope this guide helps you get started.

Update: I have written an updated blog post for the slightly different details of adding to a web forms project with an ASP.NET MVC 3 project.

1. Add references

Right click on your web root project in Visual Studio (2010 in my case) and add the following references:
  • System.Web.Routing
  • System.Web.Abstractions
  • System.Web.Mvc

2. Configuration

Make your web.config look like this. Obviously not exactly like this, don't just paste this over the top of your glorious web.config. I'm just highlighting the necessary points that need to be fitted into your existing web.config:
<system.web>
  <compilation debug="true" targetFramework="4.0">
    <assemblies>
      <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add assembly="System.Web.Abstractions,Version=4.0.0.0, Culture=neutral,PublicKeyToken=31BF3856AD364E35"/>
      <add assembly="System.Web.Routing,Version=4.0.0.0, Culture=neutral,PublicKeyToken=31BF3856AD364E35"/>
    </assemblies>
  </compilation>
  <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID">
    <namespaces>
      <add namespace="System.Web.Mvc"/>
      <add namespace="System.Web.Mvc.Ajax"/>
      <add namespace="System.Web.Mvc.Html"/>
      <add namespace="System.Web.Routing"/>
    </namespaces>
  </pages>
</system.web>
<system.webServer>
  <modules>
    <remove name="UrlRoutingModule-4.0" />
    <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
  </modules>
</system.webServer>
<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
      <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

Update: I have changed my recommendation against using <modules runAllManagedModulesForAllRequests="true"> in favour of adding the UrlRoutingModule-4.0 module with a blank precondition as I explain in my article Don't use runAllManagedModulesForAllRequests="true" for MVC routing.

3. Routing

You will need to add a global.asax file to your web application if you haven't already got one. Right click > Add > Add New Item > Global Application Class:


Now in your global.asax add these usings:
using System.Web.Mvc;
using System.Web.Routing;

Now add these lines:
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    //ignore aspx pages (web forms take care of these)
    routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");

    routes.MapRoute(
        // Route name
        "Default",
        // URL with parameters
        "{controller}/{action}/{id}",
        // Parameter defaults
        new { controller = "home", action = "index", id = "" }
        );
}

protected void Application_Start(object sender, EventArgs e)
{
    RegisterRoutes(RouteTable.Routes);
}

4. Add some standard folders to the solution

Add a folder named 'Controllers' to your web project.
Add a folder named 'Views' to your web project.
Add a folder named 'Shared' to that Views folder.
Add a web configuration file to the Views folder (web.config).
Open this web.config in the Views folder and ensure make its contents as follows:
<?xml version="1.0"?>

<configuration>
  <system.web>
    <httpHandlers>
      <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
    </httpHandlers>

    <!--
        Enabling request validation in view pages would cause validation to occur
        after the input has already been processed by the controller. By default
        MVC performs request validation before a controller processes the input.
        To change this behavior apply the ValidateInputAttribute to a
        controller or action.
    -->
    <pages
        validateRequest="false"
        pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <controls>
        <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
      </controls>
    </pages>
  </system.web>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    
    <handlers>
      <remove name="BlockViewHandler"/>
      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
    </handlers>
  </system.webServer>
</configuration>

5. Get Visual Studio 2010 to recognise your MVC skills

If you right click the Controllers folder and select Add, you'll notice there is no Controller class to add. You need to make a change to your web project file.

Using Windows Explorer find the web project file (Web.csproj in my case) and open it in a text editor. You will need to add "{F85E285D-A4E0-4152-9332-AB1D724D3325};" to the ProjectTypeGuids element.

E.g. mine now looks like this:
<ProjectTypeGuids>{F85E285D-A4E0-4152-9332-AB1D724D3325};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>

6. Optional: Add a Controller (for a laugh)

Back to Visual Studio 2010 and right click the Controllers folder > Add > Controller... call it HomeController.

using System.Web.Mvc;

namespace Web.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewData["Message"] = "This is MVC";
            return View();
        }
    }
}

7. Optional: Add a View (just to show off)

Right click where it says return View(); and select Add View... then click Add.

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Index</title>
</head>
<body>
    <div>
        <%: ViewData["Message"] %>
    </div>
</body>
</html>

8. Optional: Try it (just to self-indulge your skills)

Now run you site and go to http://{localhost}/home

I hope this saved you the hours it took me! Please comment if you have any feedback. It would be much appreciated

More reading here if you would like to use an existing WebForms MasterPage in your new MVC project.

Follow britishdev on Twitter

Thursday 13 May 2010

Getting started with ASP.NET MVC2

About to start a new project using ASP.NET MVC 2 and Entity Framework 4. Where to get started?

I worked through the Nerd Dinner example before which was great but was MVC 1. I found this brilliant code sample and walkthrough of creating a music store using MVC 2 and Entity Framework 4 with this MVC 2 Sample Application.

I have looked over this briefly and am impressed. So I would like to share it with you. Enjoy.

Follow britishdev on Twitter

Friday 7 May 2010

How to upgrade to ASP.NET4

If you want to know how to upgrade your existing ASP.NET solution to target the ASP.NET 4 framework there are a number of steps you need to take to ensure a smooth upgrade of your website. ASP.NET 4 is a brand new framework, it is not just an extension of ASP.NET 3.5. This means there are a number of steps you need to know to know how to successfully upgrade to the new .NET4 runtime smoothly.

Here is a list of challenges I encountered whilst upgrading the lovemoney.com solution to ASP.NET 4 from ASP.NET 3.5. I hope you find this an important reference or guide if you come to do the same thing:

1. Set your application pool to use .NET 4
2. Changing the browser definitions
3. Running .NET 4 application as a child under a .NET 3.5 root parent site in IIS 7
4. Targeting ASP.NET 3.5 with MSTest
5. Potentially dangerous request validation
6. MembershipUser and other System.Web.Security types have moved namespace
7. Publishing a project with missing files


1. Set your application pool to use .NET 4

You may run into an error saying "Unrecognized attribute 'targetFramework'. Note that attribute names are case-sensitive." with a description of "An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately."

This is indicating that your solution is targeting the .NET 4 framework but is still using the .NET 2 framework. To fix this you need to:
  1. Go to IIS
  2. Find the Application Pool you are using
  3. Right click it and select Basic Settings
  4. Change the target framework to .NET Framework v4 as illustrated

More info on unrecognized targetFramework attribute in ASP.NET 4


2. Changing the browser definitions

You could receive an error message of "The browser or gateway element with ID 'Safari1Plus' cannot be found." and a description of "An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately."

This is because the browser definitions have been updated for ASP.NET 4 from the 5 year old ASP.NET 2 browser definitions.

If you have not added to your browser definitions in any way your site should work okay but be aware that some browsers may be identified more (or maybe less) accurately. If you added to your browser definitions prior to the .NET4 upgrade (i.e. there are files in your App_Browser folder) you may recieve errors. These errors will be immediately apparent runtime errors.

If you are getting these runtime errors you can fix them in one of two ways:
  • Remove the browser definitions you have in the web root's App_Browsers folder
  • Copy the old browser definition files from the old location of C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\Browsers to C:\Windows\Microsoft.NET\Framework\v4.0.[whatever]\Config\Browsers (you will also need to do the same for the Framework64 version if you have one) and then run the Aspnet_regbrowsers.exe command-line tool.

More info on browser or gateway element not being found in browser definitions


3. Running .NET 4 application as a child under a .NET 3.5 root parent site in IIS 7

You get the error of "The requested page cannot be accessed because the related configuration data for the page is invalid." and a config error of "There is a duplicate 'system.web.extensions/scripting/scriptResourceHandler' section defined"

This is because your web.config of your child site or application is inheriting from you parent application or site. This would happen if you have made an ASP.NET 4 application a child of an ASP.NET 2 or 3.5 site.

A (filthy) workaround for this problem would be to:
  1. Move the whole <configSections> section into the machine level web.config at C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\
  2. stop the web.config inheritance to wrap the whole configuration section in a <location inheritInChildApplications="false">

This feel very messy and personally I am not a fan of changing machine level configs, I went for upgrading the root site.
If you want more detailed info than this please feel free to bore dive into ASP.NET 4 Child Applications Fail to Start When Under ASP.NET 2.0 or ASP.NET 3.5 Applications - (and good luck!)

More info on duplicate section defined in a child .NET 4 application


4. Targeting ASP.NET 3.5 with MSTest

You may run into an "attempted re-targeting of the project has been cancelled. You cannot change the specified .NET framework version or profile for a test project" error when you try to target the ASP.NET 3.5 framework in a Microsoft Unit Test project.

Seriously, that is the end of this step. You just can't do it. Deal with it. This comes from Microsoft's mouth too (slightly more elegantly, I will concede). But, the fact remains: You cannot use Visual Studio 2010 AND target ASP.NET 3.5 AND use MS Test.

You will either have to exclude the Unit Test project from your solution or not use VS2010!

More info on changing the specified .NET framework version or profile for a test project


5. Potentially dangerous request validation

You can find yourself with an error of "A potentially dangerous Request.Form value was detected from the client" on a page which is set to ValidateRequest="false".

Previously putting ValidateRequest="false" in the Page declaration solved this problem. In .NET4 this is not the case. Simple work around though. You simply need to stick the following code in your web.config:
<system.web>
    <httpRuntime requestValidationMode="2.0" />
    <!-- everything else -->
</system.web>

This will set the request validation back to how you are used to. However, why not use this opportunity to solve this potential security properly? Or maybe use a <location inheritInChildApplications="false"> to wrap this code so that it is only relevant to the specific page that needs it?

More info on potentially dangerous request in ASP.NET 4 upgrade


6. MembershipUser and other System.Web.Security types have moved namespace

You could get a build time error of "The type name 'MembershipProvider' could not be found in the namespace 'System.Web.Security'. This type has been forwarded to assembly 'System.Web.ApplicationServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' Consider adding a reference to that assembly. ASP.NET4." after upgrading.

To fix this you just need to add a reference to the erroring project(s).
  1. Right click the References folder
  2. Click Add Reference...
  3. Under the .NET tab find and select System.Web.ApplicationServices

You may now need to resolve the references to MembershipUser (or other types) but you should be good to go.

More info on Membership provider not being found in System.Web.Security


7. Publishing a project with missing files

It seems like Visual Studio 2010 is a lot less forgiving when it comes to the project file referencing a file (static (e.g. an image) or otherwise) that does not actually exist when publishing.

You will have to go about your solution excluding all of these dud references. One by one too! Publish then exclude, publish, exclude, publish, exclude etc. until it published okay and stops complaining.

Summary and more...

This is a list of the complications I encountered during the upgrade process and how to solve each one. There are other complications too that I didn't personally encounter which you can read a white paper on ASP.NET 4 breaking changes from Microsoft themselves.

Hope this helps - if it did please link to this guide.

Good luck!

Follow britishdev on Twitter