The new VS2010 Web Deployment model is very powerful. It allows you to setup all your configuration and then use one-click publish to load your web application (or just the diffs) up to your server. Scott Hanselman gave a great talk on this at MIX that I highly recommend — http://www.hanselman.com/blog/WebDeploymentMadeAwesomeIfYoureUsingXCopyYoureDoingItWrong.aspx
Under the covers, this is all using MSDeploy which adds all sorts of power to run commands, set ACLs, etc. Put exactly *how* to do this is not documented very well and I spent many a frustrating hour working on one simple task. How do you make the web deploy process grant the Application Pool Identity access to a modify a specific directory? Since the built in deployment resets all the permissions to Read-only, you have to figure this out or you have to manually change it every time.
A lot of the documentation, including Scott’s MIX presentation, talks about creating a manifest.xml file. Unfortunately this only applies if you’re making calls to MSDeploy manually. When VS2010 prepares a package, it does its own thing and creates its own manifest.xml (actually called <project>.source.manifest which then feeds to archive.xml in the zip file). But all this is running through the “Web Publishing Pipeline” (WPP) and you can jump into the pipeline yourself.
Turns out this is quite easy. You need to create a <ProjectName>.wpp.targets file in the root of your web project. I made mine part of the project and set it to Build Action = None, Copy to Output Directory = Do not copy.
The content of my file is as follows:
Lets talk about the different sections of this.
This line just introduces a flag we can use if we ever want to turn this process off. Is is referenced in the Condition property for our Target.
<AfterAddIisSettingAndFileContentsToSourceManifest Condition="'$(AfterAddIisSettingAndFileContentsToSourceManifest)'==''"> $(AfterAddIisSettingAndFileContentsToSourceManifest); SetCustomACLs; </AfterAddIisSettingAndFileContentsToSourceManifest>
These lines inject our task into the pipeline. Some examples talked about doing it on AfterAddContentPathToSourceManifest, but I found this could inject our SetACL command before the IISApp declaration. Putting it AfterAddIisSettingAndFileContentsToSourceManifest meant our code would be right after all the default stuff the deployment will automatically do.
<Target Name="SetCustomACLs" Condition="'$(IncludeCustomACLs)'=='TRUE'">
This declares our custom target. The Name is whatever we want it to be, and the Condition looks at our custom flag.
<MsDeploySourceManifest Include="setAcl" Condition="$(IncludeSetAclProviderOnDestination)">
This command tells MSDeploy to do the “setAcl” command. All ACLs in the default pipeline are set based on the IncludeSetAclProviderOnDestination flag, so we’ll honor that.
This controls what we want to change the ACL on. In this example we’re changing the web application root, so $(_MSDeployDirPath_FullPath) is all we need. If we wanted a certain file, we could do something like $(_MSDeployDirPath_FullPath)\Files\myfile.txt.
This is where you set the rights you want. Options are combinations of Execute, Write, Read, ReadAndExecute, and Modify.
We need to specify if this is a Directory or a File.
These are needed to make our earlier settings be sent to MSDeploy.
We could also add entries for setAclUser. The default is the application pool’s identity, which is usually what you need.
And that’s all there is to it. When you publish your project, this file will be read and you custom ACL entries will be injected. To see that they really are, you can go to the directory where it creates the zip file before publishing (specified in your Package/Publish Settings, usually obj/Release/Package or obj/Debug/Package). There will be a <Project>.SourceManifest.xml file. Open it and you’ll see lines for the normal setACL commands as well as the one you injected (we injected the last line in the file below).
<?xml version="1.0" encoding="utf-8"?> <sitemanifest> <IisApp path="C:\Users\Kevin\Documents\Visual Studio 2010\Projects\MotoBlur\MotoBlur\obj\Release\Package\PackageTmp" managedRuntimeVersion="v4.0" /> <setAcl path="C:\Users\Kevin\Documents\Visual Studio 2010\Projects\MotoBlur\MotoBlur\obj\Release\Package\PackageTmp" setAclResourceType="Directory" /> <setAcl path="C:\Users\Kevin\Documents\Visual Studio 2010\Projects\MotoBlur\MotoBlur\obj\Release\Package\PackageTmp" setAclUser="anonymousAuthenticationUser" setAclResourceType="Directory" /> <setAcl path="C:\Users\Kevin\Documents\Visual Studio 2010\Projects\MotoBlur\MotoBlur\obj\Release\Package\PackageTmp" setAclResourceType="Directory" setAclAccess="Read,Write,Modify" /> </sitemanifest>
Special thanks go to:
- Xinyang Qiu whose blog teaches how to use the *.wpp.targets file: http://blogs.msdn.com/b/webdevtools/archive/2010/02/09/how-to-extend-target-file-to-include-registry-settings-for-web-project-package.aspx
- Vishal Joshi whose blog teaches about how the process works under the covers: http://vishaljoshi.blogspot.com/2009/03/how-does-web-deployment-with-vs-10.html
- Tali Smith whose post on Learn.IIS.Net teaches the settings for SetACL: http://learn.iis.net/page.aspx/742/set-acls-through-the-manifestxml-file/