Scott Hanselman

BIN Deploying ASP.NET MVC 3 with Razor to a Windows Server without MVC installed

November 24, 2010 Comment on this post [39] Posted in ASP.NET | ASP.NET MVC
Sponsored By

If someone says "just bin Deploy it" they mean "deploy the application with the dependencies copied into the application's /bin folder, rather than running an MSI that installs the dependencies into the Global Assembly Cache (GAC)."

You may not have administrative control over your Web Server and your host may not want you running installers when new stuff like ASP.NET MVC 3 and Razor comes out. You'll want to "bin deploy" these new technologies.

Here's two ways. The simple way and The Awesome Way.

The Manual Way to BIN Deploy ASP.NET MVC 3 with Razor

On your development machine that has ASP.NET MVC 3 installed you have a C:\Program Files\Microsoft ASP.NET\ASP.NET MVC 3 folder and a C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages folder. In those folders are "Assemblies" folders.

Windows Explorer showing the Assemblies that ASP.NET MVC and Web Pages needs for BIN Deployment

ASP.NET MVC itself references these additional assemblies.

  • System.Web.Mvc (well, we ARE this assembly, actually)
  • Microsoft.Web.Infrastructure
  • System.Web.Razor
  • System.Web.WebPages
  • System.Web.WebPages.Razor

And the default Web.config for projects also expects:

  • System.Web.Helpers

After you deploy your ASP.NET MVC 3 Razor application, you'll need to manually copy these five assemblies to the \bin folder of your deployed application.

NOTE: It's possible to just reference these assemblies directly from your application, then click properties on each one and set copyLocal=true. Then they'd get automatically copied to the bin folder. However, I have a problem with that philosophically. Your app doesn't need a reference to these assemblies. It's assemblies your app depends on. A depends on B that depends on C. Why should A manually set a dependency on C just to get better deployment? More on this, well, now.

Now, you likely remember that "If you're using XCOPY for deployment, you're doing it wrong" so you're likely wondering how to make this deployment process less manual and more awesome.

The Alpha-Geek Show-Off Fancy-Pants Future-Proofed Way to BIN Deploy ASP.NET MVC 3 with Razor

I created a custom Windows 7 Virtual Machine that had only IIS7 and .NET 4 installed, plus Web Deploy, and nothing else in order to test this scenario. This machine has never seen ASP.NET MVC 3 or Razor and we're not installing anything on it. It's our pretend "shared host."

My custom Virtual Machine without ASP.NET MVC installed

In my ASP.NET MVC Application, I'm going to create a folder called "_bin_deployableAssemblies." Yes, that's a underscore in the front. IIS will not serve from folders whose first character is an underscore. You can thanks FrontPage for that feature. In fact, this guarantees that even if you accidentally copy this folder up (don't) it won't be served. Apparently I got bad info on this from the IIS team. I'm looking into this statement as it's incorrect.

  • Create a _bin_deployableAssemblies folder.
  • Copy the assemblies we want bin deployed into this _bin_deployableAssemblies folder.
  • Select them all, right click and hit properties. Set their Build Action to "None."
  • You are expected to check these into source control as well.

Here's my Solution so far:

My Solution Folder View

Here comes the secret awesome sauce.

NOTE: You're reading this on some random dude's blog, so lower your expectation of support now. No, lower. Bit lower. There. Yes, that's zero support. If this accidentally formats your harddrive or deletes your source code, kick yourself hard so you'll wake up to the previous level of Inception, specifically the one where the skinny kid from Third Rock From The Sun is walking on the ceiling. Be careful. Make backups.

Get ready, because we are going into the belly of the beast. This is for VS2010, to be clear. Also, your Program Files folder will vary depending on your x86/x64 version of Windows.

  • Go into C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\WebApplications and make a copy of this folder. Put it somewhere safe.
  • Go  into C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web and make a copy of this folder. Put it somewhere safe.
  • Download this file and unzip it somewhere: FancyAndTotallyUnsupportedMSBuildFilesForBinDeployableAssemblies.zip
  • Inside is:
    • "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets"
    • "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.OnlyFilesToRunTheApp.targets"
  • Copy these new files OVER your existing ones (remember, the ones you backed up?)

Now when you build your Web Application, all the files that are in _bin_deployableAssemblies will automatically get copied into your /bin folder.

This is better than a simple Post Build Step Batch File because it works specifically with publishing. Now, you can right click on your Web Project and "Publish..." an the bin folder contain your project's build output PLUS the _bin_deployableAssemblies folder.

Build Deployment Package

I could publish directly to my Shared Host, or I can Build Deployment Package and get a ZIP file with all the things my app needs.

For me, as I have a VM (remember that I put Web Deploy on it?) and from IIS Manager just "Import Application." Some hosters have a control panel for this, but you'll likely use Web Deploy or Publish via FTP.

Import Application from inside IIS7 with WebDeploy

This is a nice, clean, self-contained way to bin deploy an ASP.NET MVC 3 application with Razor views to a host that doesn't have any of these bits installed.

INTERESTING NOTE: In a "future update to Visual Studio 2010" (that's marketing code for SP1, which I'm not allowed to say) this feature will be built in. Because with this hack we've only messed with our built-in build targets, those files we've modified will be torched (replaced) with the new Visual Studio updated files, effectively undoing what we've done here. It's a "future-proofed hack."

Enjoy!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
November 24, 2010 5:24
Hmmm... what's wrong with changing Copy Local to True in the reference properties? Then you can publish your app to a folder and xcopy/ftp that to your server. That's always worked for me. What am I missing here..?
November 24, 2010 7:51
@Chris Vann
In this case, MVC3 relies on the new ASP.NET Web Pages framework, including Razor. However, MVC3 projects don't take direct dependencies on a few of these assemblies due to the way they are dynamically loaded into the app domain during application pre-startup. You could just add a reference to them anyway and set them to copy local = true but it's kinda clunky and isn't really "correct". Moving forward, we'll have a feature in VS that utilizes API calls against these components to copy the correct assemblies required for bin deployment into the _bin_deployableDependencies folder, all through a nice GUI so you don't have to worry about it.
November 24, 2010 11:51
Does this work on Mono 2.8.1?
November 24, 2010 12:29
I disagree with your statement about XCopy deployement. As freelancer, building small web sites and application in asp.net (mvc), i get only ftp access to shared hosting server. As most of folks I work with and know. I rarely see someone with RDP or WebDeploy.
If just copying all files (after compiling/publishing site to local temp folder, of course) to ftp isn't enough and doesn't work, I'll not use does libraries, frameworks, ...
November 24, 2010 13:43
Dear Scott,

I don't give a sh*t about ASP.NET MVC (yet). I just read this blog post to have a good laugh. Are you ok with that?
November 24, 2010 15:55
Can you help me with this...

I am building a windows application and i am facing this error "Unable to install or run the application. The application require that assembly Microsoft.SqlServer.DataProfilingTask Version 10.0.0.0 be installed in the Global Assembly Cache (GAC) first." when i try to install it to another machine with Windows XP OS.

Another problem that i am facing is of remote connectivity. previously when the application got sucessfully installed it did not connect to the Server machiene with Windows server 2003 R2 OS. The firewall is off, the connection string works fine but still non of the other machien is being connected to the SQL Server Instance.

November 24, 2010 16:48
Hello Scott

My hosting provider doesn't even have .net 4.0 , and just 3.5.. Is there a work around to install .net 4.0 in same fashion ?

Thanks - Anuj Pandey
November 24, 2010 16:54
Will this still work if your host currently has MVC 2 installed?
November 24, 2010 17:58
Since yesterday I'm dealing with deploying MVC 3.0 RC app to server ( windows server 2008 SP 2 32 bit ). We migrated it from mvc 2.0 .net 4 and already I found that these few files are necessary not only for Razor, but also for default aspx view.

I'm facing similar problems to this http://stackoverflow.com/questions/2454400/net-framework-4-rtm-on-windows-server-2008-r2. Very strange is that when I have custom errors turned Off no detailed error is displayed - just the plain IIS 7.5 500 Internal Server Error. There is nothing in event viewer.
I checked ISAPI filters, privilages, almost all settings. What else can I do?
November 24, 2010 18:44
this is a perfect post scott. thanks !
November 24, 2010 22:18
Could you provide a reference to IIS / FrontPage blocking folder names starting with an underscore? I have searched on support.microsoft.com and technet.microsoft.com without any hits.
November 24, 2010 23:59
Hi Scott,

Out of curiosity, what's the role of the Microsoft.Web.Infrastructure assembly in an ASP.NET MVC 3 + Razor application, and why isn't it called System.Web.Infrastructure?

Thanks!

PS. Shouldn't NuGet be able to handle this sort of scenario?
November 25, 2010 0:42
I don't quite get the reluctance to use project references to the DLLs in question with copy local, especially since these DLLs are in the dependency chain for MVC. This was a very easy fix that made web deploy work smoothly (for me at least). This alternate route seems overly complex.
November 25, 2010 1:57
Michael - Some of the DLLs may be loaded dynamically, or only used in specific scenarios. It's simply not correct to refer to a DLL directly if you don't have a direct need to. Also, there are some instances where referencing a DLL directly could cause problem laster. I realize that this is a goofy hack *for now* but as I said, it's totally automatic in Visual Studio 2010 SP1, so you'll just make a folder and put stuff in it, and it'll work.

Anonymous OpenID guy - I'm being told that the IIS guy who told me that was mistaken about the underscores. I'm trying to get confirmation now.

Michiel - NuGet could totally be used to package up a bunch of DLLs and put them in your project. However, these DLLs are already on your machine...other than making a custom PowerShell script and using it to copy the DLLs in, there's not much for NuGet to do here.

Lukasz - Are you sure that you're in the right AppPool? Most of my 500 errors meant that my app was in a 2.0 app pool. Let me know.

Bobby - Yes, as long as your MVC3 project is referencing the right DLLs and those DLLs are in the bin folder just like in this post. It should just work. Let me know.

Anuj - No, I'm sorry. Installing .NET 4 is a bigger deal than bin deploying. That's something your host will need to do.

Erik - I'm not sure how much of MSBuild is on Mono. You'd have to ask them. You could simulate the same behavior with a Postbuild Event or shell script.

Hrvoje - WebDeploy can use FTP so you can get the best of both worlds.
November 25, 2010 15:51
Yes application pool is for .net 4.0.

Now I got error 500.19 with detail "Config Error Cannot read configuration file due to insufficient permissions". The problems is that we have user with write/read rights to folders and DB and it's selected as Identity in application pool. There were some changes in IIS 7.5 in win server 2008 R2 (which we using) that we have also add rights to folders for IIS_USRS group.
But in our case folders with application is on different server and we can't add (we can't select )) these group to folder permissions. But the strange thing is that with the same config MVC 2.0 app (.net 2.0) is working.
November 25, 2010 18:12
Looking forward, then, to having the DLL support for bin deploy in WebDeploy in SP1... other thought is that WebDeploy doesn't have to delete existing files before each deploy. So wouldn't it work to copy these DLLs to the target folder on the server once and then just leave them there? That is, rather than hacking MSBuild or project references?
November 26, 2010 3:06
Once you've added the dlls to your project, couldn't you simply set 'Copy to Output Directory' to 'Copy if newer'? (Not the same thing as adding a reference with Copy Local=true)

November 27, 2010 7:06
I tried to publish my ASP .NET MVC 3 RC1 project in Visual Studio 2010, and it did not publish all of my Razor Views. It only published one of them. What the heck?
November 27, 2010 22:25
Never mind. It appears that MVC 3 pre-RC1 did not default to .cshtml files to Content type so they were not being published.
November 30, 2010 0:20
Hey Scott...I'm migrating a legacy ASP.NET 2.0 web app to ASP.NET 4.0 / MVC 3.0 ... I still need to have support for the 2.0 code but want to use the Razor view engine. Will I need two app pool in IIS 6? For that matter, will MVC 3.0 and Razor work in IIS 6?
November 30, 2010 16:58
For some reason when I try doing this, my dll files inside the _bin_deployableAssemblies never get copied to my bin folder upon deployment. I can see the Publish building, doing web.config transformations, uploading, and completing successfully, however the files just aren't there.

I have double-checked the _bin_deployableAssemblies folder name, made sure I overwrote the 2 .targets file on my system (I can see the differences in my backup copy and the new copy in BeyondCompare). I verified that the Build Action for the dlls are "None".

For some reason, I have to copy those dlls manually to the server still :(
November 30, 2010 17:12
My apologies, apparently you have to close and re-open Visual Studio after messing with the .targets files. After completely shutting it down and re-opening, it publishes those files.

One issue I do notice, is that if you use SVN as your source control client, it copies *everything* from the _bin_deployableAssemblies, including the .svn folder, making some rather interesting looking results. Git would be unaffected.
December 01, 2010 18:38
Can you refer a good sample application which uses MVC 3 Razor with master detail like customer-order-orderdetail example mvcmusicstore.

Thanks
December 01, 2010 23:27
Thank you for enabling me to run MVC 3 on web hosting server.
One small problem, you mentioned copying the 5 dll to bin folder. I also had to copy System.Web.Mvc.dll to bin folder to have application run on ARVIXE web hosting.


December 01, 2010 23:47
To Lukasz Jarmulowicz
I was getting a 500.19 error until I changed ASP.NET to 4.0 (Integrated Pipeline) on ARVIXE web host. MVC 3 runs ok now after copying 6 dll files to bin directory.
If there is a direct way to reply to Lukasz comment, please tell me as I did not know of any other way to reply than posting a comment here.
December 13, 2010 17:56
This stopped working for me for MVC3 RC2. Getting
Method not found: 'System.String System.Web.Mvc.TagBuilder.CreateSanitizedId(System.String)'.


Ahh, I had MVC3 RC1 installed on my server. Uninstalling all traces of it helped, though I don't understand why the bin directory didn't take precedence over old-and-busted.

Also, wow, lots of new dll's needed for the _bin_deployableAssemblies directory.

Odd, couldn't use google's openid, said

414 Request-URI Too Large

The requested URL /accounts/TokenAuth... is too large to process.

hope there's no secret info in this url:

https://www.google.com/accounts/TokenAuth?service=blogger&auth=APh-3Fw8CIOyWm3rkrr_vwBa6ZZcdjL1UdUX7R7RFc6yF-RGJTe2u-h-rcyYRaf0VPwo1omvcweZ4OdfJxU8oAZ2wQR95FL5K41P0AmX7QXoyT5nI8-I0oJn8sh6MTrigm1MzdVKHYBP7GgrnKJMTP7uIAzaybmpYDjNcb0BADB9MHCANdqI2mh6ULiK4IHx9_Da8IkpFPX9fE5jT41E312tOuS53Txk2H3pV9hA9gwB9FRS-03x1P3nFjTY_NwbUjXUzULTUuS1kK5PuBRykY_PHNoi5yXgoV8hQXflqN_q1GBJ41hW6K87r6TYFWg69W-WGN5T6klITxvwcTUu4bfJn3wQPGvc4_iwKhwFiq8z16uJYLiUqTE2mcwHGd1ZM23rxRl4BDHFleyutO7nTTZHSmDk8QALUAQo07u_VQf4FVn1-b-6RHqKaGX5MBFnBNnX0BBerh8DaAEQFtcrXFYAXWZ_JX5byhXBhuFhQjEdmdz4-GHdJ3eJg1vHhoT0K1tHHBki0nyytaIEpfm0MFiGoVfAc3hJjNmzlerG5PlYJ0tddwgApmjN5wsOJEo7gOD-RoWZYCGlhVtu8VCzslNXSNfPDVQwcFA16HWjLzN4wtJGq1BHBk1sygHVeaVnGao1_YMcphFKSPdunsSctjVfeq6UOA22LZFLLNxn4mUxBiQaTkgFfBuKwjikjP6JSSAhwh9VVk5tsV2Ba1s_BT-hZfdbDU70dg,,%0A&source=blogger&continue=https://www.blogger.com/loginz%3Fd%3D%252Fopenid-confirm.g%253Fidentity%253Dhttp%25253A%25252F%25252Fblog.mateli.ch%25252F%2526realm%253Dhttp%25253A%25252F%25252Fwww.hanselman.com%25252Fblog%25252F%2526openIdSetupToken%253Doidrp.identity%25253Dhttp%2525253A%2525252F%2525252Fblog.mateli.ch%2525252F%252526oidrp.return_to%25253Dhttp%2525253A%2525252F%2525252Fwww.hanselman.com%2525252Fblog%2525252FCommentView.aspx%2525253Ftitle%2525253DBINDeployingASPNETMVC3WithRazorToAWindowsServerWithoutMVCInstalled%25252526dnoa.userSuppliedIdentifier%2525253Dhttp%252525253A%252525252F%252525252Fblog.mateli.ch%25252526dnoa.op_endpoint%2525253Dhttp%252525253A%252525252F%252525252Fwww.blogger.com%252525252Fopenid-server.g%25252526dnoa.claimed_id%2525253Dhttp%252525253A%252525252F%252525252Fblog.mateli.ch%252525252F%25252526dnoa.request_nonce%2525253DuWgWBeRozQiCayxPqNHI4EA0JZHjTv5B%25252526dnoa.return_to_sig_handle%2525253D%252525257B634278451076294841%252525257D%252525257BEawgmQ%252525253D%252525253D%252525257D%25252526dnoa.return_to_sig%2525253DGB8jtBFZj5QXT17Asin9wEb4jZT%252525252BMuTrvp5Ji8UtM04pd%252525252FNEG7ppVXCMDjoiZrQUerKO6Qg%252525252BWeWM3dhJ0MMI%252525252Bg%252525253D%252525253D%252526oidrp.trust_root%25253Dhttp%2525253A%2525252F%2525252Fwww.hanselman.com%2525252Fblog%2525252F%252526oidrp.assoc_handle%25253Doida-1292248307133-1687416738%26a%3DALL&aplinsu=1
December 14, 2010 13:55
Are the following assemblies still sufficient for MVC3 RC2 manual bin deployment?

System.Web.Mvc (well, we ARE this assembly, actually)
Microsoft.Web.Infrastructure
System.Web.Razor
System.Web.WebPages
System.Web.WebPages.Razor
System.Web.Helpers


Cheers
Kev
December 14, 2010 18:27
It seems like System.Web.WebPages.Deployment is also a required assembly in addition to the 6 mentioned in this article for RC2.
December 17, 2010 3:39
@paul - that seems work nicely.
December 18, 2010 18:50
@paul
you are right about that. It does need the System.Web.WebPages.Deployment.dll
I run into an error like ;

Could not load file or assembly 'System.Web.WebPages.Deployment, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.

I made a little blog post on that;

http://www.tugberkugurlu.com/archive/deployment-of-asp-net-mvc-rc-2-application-on-a-shared-hosting-environment-without-begging-the-hosting-company

@shanselman
Hope it is ok scott. It seems that the post has the same topic as yours (but I did put your post's link inside mine)
December 22, 2010 11:42
My ASP.NET MVC project has indirect dependencies on some other projects in my solution. But unlike common scenario there is no solid chain of dependencies between projects, these dependencies are broken by IoC container therefore some assemblies should be loaded by Assembly.Load(<file name from config file or auto discovery>) at some time. So there is the same problem for such projects: their's binaries does not automatically appear in web bin folder. What you suggest in this case? Will upcoming VS 2010 feature cover this scenario?
January 08, 2011 1:28
This caused my Setup projects to fail to build. Right or wrong, in the Microsoft.Web.Publishing.OnlyFilesToRunTheApp.targets, I changed the CollectFilesFrom_binDeployableAssembliesDependsOn opening tag to the following:

<CollectFilesFrom_binDeployableAssembliesDependsOn Condition="'$(CollectFilesFrom_binDeployableAssembliesDependsOn)'=='' And Exists('$(MSBuildProjectDirectory)\_bin_deployableAssemblies')">

This allows the Setup projects to build and seems to still allow the bin deployment functionality to work.
February 16, 2011 20:39
Thanks for the manual steps to bin deploy MVC3 Razor. What if I also have a SQL Server Compact .sdf file? Where do I copy that and how does that change my connection string?

<add name="myDB" connectionString="data source=|DataDirectory|\myDB.sdf" providerName="System.Data.SqlServerCe.4.0" />

Thank you,

Mark
March 04, 2011 12:54
@Matt,

If you adapt : <CreateItem Include="$(MSBuildProjectDirectory)\_bin_deployableAssemblies\**\*.*" to <CreateItem Include="$(MSBuildProjectDirectory)\_bin_deployableAssemblies\**\*.dll" in the file Microsoft.WebApplication.targets, it will only copy the dll's and not the _svn folder.

@Scott,
Will the future Visual Studio SP1 take in account the "not wanted" folders/files from source control systems?
April 06, 2011 5:53
May I know about the default document of MVC3 Razor web application? When I deploy the App, how should I set the default document? There are no document in wwwroot folder.
June 11, 2011 0:33
Ok, these didn't exist so i created them and then dropped the files into the respective folders.

Go into C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\WebApplications and make a copy of this folder. Put it somewhere safe.
Go into C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web and make a copy of this folder. Put it somewhere safe.

Cleaned solution, did build and then a deploy to my local IIS 7.5 instance (windows 7, asp.net 4, mvc3 and & razor setup). Refreshed page and did not find the default document.

This runs perfectly in VS10.

Ideas?

Thanks,

Jose
June 11, 2011 1:44
So I was able to get it working at the root level of my IIS instance but when i had a virtual app it did not like it.

when deploying my mvc3 web app to http://localhost/ it works
when deploying the same app to a virtual web app to http://localhost/catalog it doesn't work

not sure what I'm missing but any tips to trouble shoot would be greatly appreciated.
June 23, 2011 11:29
Thanks, missing assemblies on deployment really had me frustrated - previous deploys had worked fine - I was already on a path of rolling back changes
August 14, 2011 12:55
Hi
Thanx so much for you'r great and simple article, that save me. :)
Sincerely
Ali
Ali

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.