BIN Deploying ASP.NET MVC 3 with Razor to a Windows Server without MVC installed
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.
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."
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:
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.
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.
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.
About Newsletter
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.
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, ...
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?
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.
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
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?
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?
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.
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.
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 :(
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.
Thanks
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.
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.
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
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
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)
<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.
<add name="myDB" connectionString="data source=|DataDirectory|\myDB.sdf" providerName="System.Data.SqlServerCe.4.0" />
Thank you,
Mark
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?
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
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.
Thanx so much for you'r great and simple article, that save me. :)
Sincerely
Ali
Comments are closed.