Using web.config from base folder and not bin folder - asp.net

I have an asp.net mvc web page. I'm using config transforms with it. The config transform in the bin directory is correct. However, when I debug with IIS express, all the app settings being used are actually from the original web.config, not the transformed web.config in the bin folder. If I rename the web.config to something else in the root folder, debugging will halt as soon as it tries to read a connection string because it says it's not initialized. What is the problem?

Transformations only apply when you publish the project. However their is a hack to it
You can try using the below code. Your original configuration should be in Web.Base.Config
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\WebApplications\Microsoft.WebApplication.targets" />
<Target Name="BeforeBuild">
<TransformXml
Source="Web.Base.config"
Transform="Web.$(Configuration).config"
Destination="Web.config" />
</Target>
You can also refer to below URL as sometime it makes transformation twice and you need to add steps for beforebuild
https://sebnilsson.com/blog/asp-net-transform-web-config-with-debug-release-on-build/

Related

Webdeploy - precompile asp.net application error with excluded connectionstrings in excluded app_data folder

I try to use webdeploy for our asp.net application. Today I tried to activate the "Precompile during publishing" flag. It seems that this flag doesn`t work together with the "Exclude files from the App_Data folder".
Before I activated the precompiling in webdeploy everything worked fine. If I remove the configSource from my connectionStrings and run the webdeploy with precompiling it works again.
The problem is that I have to load the external connectionstring file, because it will be managed by the administrators for production-environments.
The error message I get from webdeploy is:
"An error occurred loading a configuration file: Directory 'C:\MyProject\obj\Release\AspnetCompileMerge\Source\App_Data' does not exist. Failed to start monitoring file changes."
My current setup is the following:
Web.Config:
<configuration>
<!-- Section stuff here -->
<connectionStrings configSource="App_Data\DBConnection.xml" />
<!-- More stuff here -->
</configuration>
New webdeploy settings:
Try excluding the config file from the package by adding the following MSBuild script to either your project file or a wpp.targets file:
<ItemGroup>
<ExcludeFromPackageFiles Include="App_Data\DBConnection.xml">
<FromTarget>Project</FromTarget>
</ExcludeFromPackageFiles>
</ItemGroup>
Hey this did not work for us. But we also updated our tfs in the last days and we had a look into the webdeploy parameters which can be set easily with the release Manager from our new tfs. So we just readded he connectionstrings into the web.config and than we compile everything. In the end we decided where it's going to be deployed and than we set automatically the connectionstrings, which are hidden for us Devs.

Set ACLs during Web Deployment via MSBuild

I have a mostly working web build-and-deploy configuration running in TeamCity, that basically uses MSBuild to automatically deploy the site to a web server. MSDeploy sets everything to Readonly on the target server by default, and I need the AppPool identity to have write access to just one folder.
I found an article by Kevin leetham that gets me 90% of the way there. Kevin describes how it is possible to hook into the MSBuild Web Publish Pipeline by creating a file called ProjectName.wpp.targets, along these lines:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!--Extends the AfterAddIisSettingAndFileContentsToSourceManifest action do also set ACLs -->
<IncludeCustomACLs>TRUE</IncludeCustomACLs>
<AfterAddIisSettingAndFileContentsToSourceManifest Condition="'$(AfterAddIisSettingAndFileContentsToSourceManifest)'==''">
$(AfterAddIisSettingAndFileContentsToSourceManifest);
SetCustomACLs;
</AfterAddIisSettingAndFileContentsToSourceManifest>
</PropertyGroup>
<Target Name="SetCustomACLs" Condition="'$(IncludeCustomACLs)'=='TRUE'">
<Message Text="Adding Custom ACls" />
<ItemGroup>
<!-- Ensure the AppPool identity has write access to the Files directory -->
<MsDeploySourceManifest Include="setAcl" Condition="$(IncludeSetAclProviderOnDestination)">
<Path>$(_MSDeployDirPath_FullPath)\files</Path>
<setAclAccess>Read,Write,Modify</setAclAccess>
<setAclResourceType>Directory</setAclResourceType>
<AdditionalProviderSettings>setAclResourceType;setAclAccess</AdditionalProviderSettings>
</MsDeploySourceManifest>
</ItemGroup>
</Target>
</Project>
This is so nearly working that it is driving me crazy. The ACL gets added to the manifest, but the problem is that it generates an absolute path based on the build location, rather than being relative to the IIS web app on the target server. the generated manifest comes out like this (some names have been changed to protect the innocent):
<?xml version="1.0" encoding="utf-8"?>
<sitemanifest>
<IisApp path="C:\SolutionPath\IisWebAppName\src\MyProjectName\obj\Release_Deploy\Package\PackageTmp" managedRuntimeVersion="v4.0" />
<setAcl path="C:\SolutionPath\IisWebAppName\src\MyProjectName\obj\Release_Deploy\Package\PackageTmp" setAclResourceType="Directory" />
<setAcl path="C:\SolutionPath\IisWebAppName\src\MyProjectName\obj\Release_Deploy\Package\PackageTmp" setAclUser="anonymousAuthenticationUser" setAclResourceType="Directory" />
<setAcl path="C:\SolutionPath\IisWebAppName\src\MyProjectName\obj\Release_Deploy\Package\PackageTmp\files" setAclResourceType="Directory" setAclAccess="Read,Write,Modify" />
</sitemanifest>
This actually looks correct, the last line is my custom ACL from teh wpp.targets file. However, when MSDeploy sends this to the target server, here's what happens:
2>Start Web Deploy Publish the Application/package to https://webhostingprovider.biz:8172/msdeploy.axd?site=IisWebAppName ...
2>Adding sitemanifest (sitemanifest).
2>Adding ACL's for path (IisWebAppName)
2>Adding ACL's for path (IisWebAppName)
2>Adding ACL's for path (C:\SolutionPath\IisWebAppname\src\MyProjectName\obj\Release_Deploy\Package\PackageTmp\files)
2>C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.targets(4377,5): Error ERROR_USER_NOT_AUTHORIZED_FOR_SETACL: Web deployment task failed. (Could not complete an operation with the specified provider ("setAcl") when connecting using the Web Management Service. This can occur if the server administrator has not authorized the user for this operation. setAcl http://go.microsoft.com/fwlink/?LinkId=178034
The whole thing falls over on my custom ACL path, which comes out using an absolute path name instead of being relative to IisWebAppName. I cannot figure out why!!
Help please :)
You need to create a ProviderPath parameter with a DefaultValue that takes it's value of another parameter using the {param name} syntax.
Here's a helper I included on another question that performs all the actions:
<ItemDefinitionGroup>
<AdditionalAcls>
<AclAccess>Write</AclAccess>
<ResourceType>Directory</ResourceType>
</AdditionalAcls>
</ItemDefinitionGroup>
<PropertyGroup>
<AfterAddIisSettingAndFileContentsToSourceManifest>
$(AfterAddIisSettingAndFileContentsToSourceManifest);
AddAdditionalAclsToSourceManifest;
</AfterAddIisSettingAndFileContentsToSourceManifest>
<AfterAddIisAndContentDeclareParametersItems>
$(AfterAddIisAndContentDeclareParametersItems);
AddAdditionalAclsDeclareParameterItems
</AfterAddIisAndContentDeclareParametersItems>
</PropertyGroup>
<Target Name="AddAdditionalAclsToSourceManifest">
<ItemGroup Condition="'#(AdditionalAcls)' != ''">
<MsDeploySourceManifest Include="setAcl">
<Path>$(_MSDeployDirPath_FullPath)\%(AdditionalAcls.Identity)</Path>
<setAclResourceType Condition="'%(AdditionalAcls.ResourceType)' != ''">%(AdditionalAcls.ResourceType)</setAclResourceType>
<setAclAccess>%(AdditionalAcls.AclAccess)</setAclAccess>
<AdditionalProviderSettings>setAclResourceType;setAclAccess</AdditionalProviderSettings>
</MsDeploySourceManifest>
</ItemGroup>
</Target>
<Target Name="AddAdditionalAclsDeclareParameterItems">
<ItemGroup Condition="'#(AdditionalAcls)' != ''">
<MsDeployDeclareParameters Include="Add %(AdditionalAcls.AclAccess) permission to %(AdditionalAcls.Identity) Folder">
<Kind>ProviderPath</Kind>
<Scope>setAcl</Scope>
<Match>^$(_EscapeRegEx_MSDeployDirPath)\\#(AdditionalAcls)$</Match>
<Description>Add %(AdditionalAcls.AclAccess) permission to %(AdditionalAcls.Identity) Folder</Description>
<DefaultValue>{$(_MsDeployParameterNameForContentPath)}/#(AdditionalAcls)</DefaultValue>
<DestinationContentPath>$(_DestinationContentPath)/#(AdditionalAcls)</DestinationContentPath>
<Tags>Hidden</Tags>
<ExcludeFromSetParameter>True</ExcludeFromSetParameter>
<Priority>$(VsSetAclPriority)</Priority>
</MsDeployDeclareParameters>
</ItemGroup>
</Target>
You can use it by declaring:
<ItemGroup>
<AdditionalAcls Include="MyRelativeWritableDirectory" />
</ItemGroup>
Please note that this solution only currently works if you don't need a backslash in the path (ie. if it's a root directory only). If you need a sub-directory, you'll need to steal the trick I use for "SkipDeleteItems" (later in that answer) to add regex-escaped path metadata to each item.

How do I get msdeploy to create App_Data if it doesn't exist, but not delete any contents of the remote directory?

I have an application setup with the following Package/Publish Web settings:
Only files needed to run this application
(unchecked) Exclude generated debug symbols
(checked) Exclude files from the App_Data folder
(checked) Include all databases configured in Package/Publish SQL tab - note I do not have any databases configured
(unchecked) include IIS settings as configured in IIS Express
In the project, I have an App_Data folder setup, primarily to handle application logs.
The behavior I'd like to see (and expect) is the following:
On initial deploy to a brand new server, the application is copied and an App_Data folder is created with write permissions assigned for the application.
On subsequent deployments, the App_Data folder is ignored because it already exists and the "Exclude files from the App_Data folder" is checked.
However, msdeploy does not appear to do step #1 (step 2 is fine if I create the folder manually). I've been unable to find any documentation on the web besides this unanswered so question that seems to confirm the behavior I see.
How do I get msdeploy to create App_Data and assign permissions on initial deployment in this scenario?
Getting App_Data deployed when starting from scratch
#tdykstra got this part right. To get App_Data out there (and ACLs set automatically), I did the following:
Adding a placeholder file in App_Data
Set the build action to content on the placeholder (my placeholder file has text in it to let people stumbling across it know why it's there).
Unchecked "Exclude files from the App_Data folder" on the Package/Publish Web tab of the project properties in VS 2010
This gets my App_Data folder created and ready for use on the server. However, it will result in all my files getting deleted whenever I republish. This is problem #2 in my question above, and pretty closely resembles this other SO question/answer.
Preventing data on the server from being deleted on subsequent publish events
There are two mechanisms in MsDeploy that can get confused (at least I confused them):
Excluding files
MsDeploy skip rules
These can both be used to solve the problem, depending on the scenario:
#tdykstra's solution will likely work if you:
Know the names of the files in App_Data in advance (e.g. a sqllite database)
Have the files included in the App_Data folder in your project
The use MsDeploy skip rules to tell MsDeploy to completely skip all deletes on the server for that directory and files in that directory. This solves the problem in all cases, but is much more involved.
Implementing MsDeploy skip rules
To implement skip rules you'll have to abandon the right-click, Deploy option in VS 2010 in favor of right-click, Package, go into a command line, re-jigger a batch file and run a command line). If you're willing to put up with this experience (I am, because I'm automating it all through a CI process), here are the details:
Edit the project file and add the following. Note that the AbsolutePath argument is a regular expression, so you can get way fancy:
<Target Name="AddCustomSkipRules">
<ItemGroup>
<MsDeploySkipRules Include="SkipDeleteAppData">
<SkipAction>Delete</SkipAction>
<ObjectName>filePath</ObjectName>
<AbsolutePath>$(_Escaped_PackageTempDir)\\App_Data\\.*</AbsolutePath>
<XPath>
</XPath>
</MsDeploySkipRules>
<MsDeploySkipRules Include="SkipDeleteAppData">
<SkipAction>Delete</SkipAction>
<ObjectName>dirPath</ObjectName>
<AbsolutePath>$(_Escaped_PackageTempDir)\\App_Data\\.*</AbsolutePath>
<XPath>
</XPath>
</MsDeploySkipRules>
</ItemGroup>
</Target>
Package, do not deploy the project. This will create a zip file and .cmd file in the target directory (defined by "Location where package will be created" on the Package/Publish Web Tab). By default, this is obj\Debug\Package (or obj\Release\Package)
Deploy the site using the the resulting command file
In my testing, you must package and run the command file. The project file tweaks will tell msbuild to put the necessary -skip rule into the command file. However, using the "publish" feature straight from VS 2010 doesn't seem to run the command file (see the warning on this walkthrough)...it calls msdeploy directly and doesn't seem to honor the project file skip rules. I believe this is the difference between VS using msbuild -T:Package and msbuild -T:MsDeployPublish to build the project, but I have not tested this.
Finally, the command file isn't quite correct, at least in VS 2010 SP1. There's a great description of what goes wrong in this SO answer, but basically, VS (or maybe the /t:Package target is a better culprit) sets up the command file to publish to the machine without specifying a site. To fix that, you'll need to somehow get "?site=sitename" (probably this is ?site=Default+Web+Site, for a full URL of https://machine:8172/MsDeploy.axd?site=Default+Web+Site) onto the end of the computerName argument.
The problem I had was that the command file (batch file) has a hard time with using site= anything on the command line since it mis-parses the command line argument (even if escaped). I don't see a way around this problem other than modifying the cmd file directly, but for testing I copied the msdeploy.exe output I saw from my failed test run and modified that to call msdeploy.exe directly without the script.
Now that it's working, my intention is to work this into my CI build processes. What I'll be doing for the final solution is:
Change my build script to use /T:Package (right now it's /T:MsDeploy)
Have a scripted search/replace routine alter the generated cmd deployment script
Run the altered deployment script
This really should be easier.
Update
Here's the scripted search/replace routine I've come up with in PowerShell:
(Get-Content "project.deploy.cmd")
-replace('^set _ArgComputerName=$'
,"set ArgComputerName=https://server:8172/MsDeploy.axd?Site=Default+Web+Site")
| Out-File -Encoding ascii deploy.cmd
Once that is run, deploy.cmd can be called (without the /M option) and it will work as expected.
Web Deploy won't create a folder if there are no files to copy to it. One workaround in your scenario would be to not use the Exclude files from the App_Data folder check box, put a dummy file in App_Data (such as a .txt file with nothing in it), and specify file exclusion rules for whatever else you have in the App_Data folder (such as your .sdf file).
On excluding individual files (you can use wildcards), see the first question in the deployment FAQ on MSDN:
http://msdn.microsoft.com/en-us/library/ee942158.aspx#can_i_exclude_specific_files_or_folders_from_deployment
On using the dummy file method for causing a folder to be created, see Making Sure that the Elmah Folder gets Deployed in this tutorial:
http://www.asp.net/web-forms/tutorials/deployment-to-a-hosting-provider/deployment-to-a-hosting-provider-configuring-project-properties-4-of-12
I managed to get it working when using the Publish Web dialog from within Visual Studio. Note: it works for any folder and not only App_Data.
This is the basic .pubxml profile:
<?xml version="1.0" encoding="utf-8"?>
<!--
This file is used by the publish/package process of your Web project. You can customize the behavior of this process
by editing this MSBuild file. In order to learn more about this please visit http://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AfterAddIisSettingAndFileContentsToSourceManifest>AddCustomSkipRules</AfterAddIisSettingAndFileContentsToSourceManifest>
<WebPublishMethod>MSDeploy</WebPublishMethod>
<LastUsedBuildConfiguration>Local</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<ExcludeApp_Data>False</ExcludeApp_Data>
<MSDeployServiceURL>localhost</MSDeployServiceURL>
<DeployIisAppPath>SuperCoolAwesomeAppName</DeployIisAppPath>
<RemoteSitePhysicalPath />
<SkipExtraFilesOnServer>False</SkipExtraFilesOnServer>
<MSDeployPublishMethod>InProc</MSDeployPublishMethod>
<EnableMSDeployBackup>False</EnableMSDeployBackup>
<UserName />
<_SavePWD>False</_SavePWD>
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
</PropertyGroup>
<PropertyGroup>
<UseMsDeployExe>true</UseMsDeployExe>
</PropertyGroup>
<Target Name="CreateEmptyFolders">
<Message Text="Adding empty folders to Files" />
<MakeDir Directories="$(_MSDeployDirPath_FullPath)\Files\Folder 1" />
<MakeDir Directories="$(_MSDeployDirPath_FullPath)\Files\Folder 2" />
<MakeDir Directories="$(_MSDeployDirPath_FullPath)\Files\Folder 3\Test"/>
</Target>
<Target Name="AddCustomSkipRules" DependsOnTargets="CreateEmptyFolders">
<Message Text="Adding Custom Skip Rules" />
<ItemGroup>
<MsDeploySkipRules Include="SkipFilesInFilesFolder">
<SkipAction>Delete</SkipAction>
<ObjectName>filePath</ObjectName>
<AbsolutePath>$(_DestinationContentPath)\\Files\\.*</AbsolutePath>
<Apply>Destination</Apply>
</MsDeploySkipRules>
<MsDeploySkipRules Include="SkipFoldersInFilesFolders">
<SkipAction></SkipAction>
<ObjectName>dirPath</ObjectName>
<AbsolutePath>$(_DestinationContentPath)\\Files\\.*\\*</AbsolutePath>
<Apply>Destination</Apply>
</MsDeploySkipRules>
</ItemGroup>
</Target>
</Project>
Here's a detailed post explaining it:
Using MsDeploy publish profile .pubxml to create an empty folder structure on IIS and skip deleting it with MsDeploySkipRules
Summarizing and simplifying Emil and Leniel answers in a concise one, if you just want to allow App_Data deploy for adds and updates, but prevents deletes, add this to your .pubxml.
<Project>
...
<PropertyGroup>
<UseMSDeployExe>true</UseMSDeployExe>
<ExcludeApp_Data>False</ExcludeApp_Data>
</PropertyGroup>
<Target Name="AddCustomSkipRules"
AfterTargets="AddIisSettingAndFileContentsToSourceManifest">
<Message Text="Adding Custom Skip Rules" />
<ItemGroup>
<MsDeploySkipRules Include="SkipDeleteAppData">
<SkipAction>Delete</SkipAction>
<ObjectName>filePath</ObjectName>
<AbsolutePath>App_Data\\.*</AbsolutePath>
</MsDeploySkipRules>
<MsDeploySkipRules Include="SkipDeleteAppData">
<SkipAction>Delete</SkipAction>
<ObjectName>dirPath</ObjectName>
<AbsolutePath>App_Data</AbsolutePath>
</MsDeploySkipRules>
</ItemGroup>
</Target>
</Project>
<UseMSDeployExe>true</UseMSDeployExe> is really needed or it will fail complaining Unrecognized skip directive 'skipaction'.

How do you specify a direct build name directory using TFS build of an ASP.net web application?

I have a TFS build set up to deploy an ASP.net project to a test server.
The build works great, and deploys to the test server fine, but instead of putting it into the \Website directory that my IIS webserver is configured for, it puts the build into \Website_20100511.6
Why is the date suffixed to the directory name? Is there a way to turn that off so I can publish directly to the \Website?
You don't want to have the build agent build to the actual location your site is running from. You need to add script to the end of the build process (tfsbuild.proj file) to take the code from the drop location and move it to the web server.
Something like this:
<Target Name="AfterDropBuild">
<Message Text="PortalFilesToPublish location is $(DropLocation)\$(BuildNumber)" Importance="Low" />
<CreateItem Include="$(DropLocation)\$(BuildNumber)\Default\_PublishedWebsites\MyWebPortal\**\*.*" Exclude="*.pdb" >
<Output ItemName="PortalFiles" TaskParameter="Include" />
</CreateItem>
<Copy
SourceFiles="#(PortalFiles)"
DestinationFiles="#(PortalFiles ->'\\testserver.test.lab\Test Lab\MyWebPortal\%(RecursiveDir)%(Filename)%(Extension)')"
ContinueOnError="true" />
</Target>

Removing web.config from subversion (ASP.NET Project)

I have a project which is source controlled using Subversion and VisualSVN. Since the version of web.config is different on the server and the developers' computers I want the file to remain on the computers but to be ignored by Subversion. I added it to the svn:ignore but it still remains (and still has a red exclamation mark too since we are not committing it).
How can I remove it from Subversion safely without it being deleted from the files system
Thanks,
Adin
you'll have to do both the remove and ignore operation
first make a backup of your local file (like #ibz said)
then remove the web.config from the repository.
then copy back the web.config to the same folder
finally use svn:ignore so that subversion does not try to add it again to the repository
since i use tortoisesvn i can't really tell you what svn commands you have to use, but using tortoisesvn it would be:
make backup
right click on web.config on the folder under source control, select TortoiseSVN | Delete
right click on web.config on the folder under source control, select SVN Commit => after this you will notice that the file is actually deleted from the file system
move up and right click on the folder under source control, select TortoiseSVN | Properties
on the properties window click new + property name "svn:ignore"; property value "web.config". accept changes
commit changes
on my .net projects i include the following exclusion with svn:ignore: bin, obj, *.suo, *.user
Ideally, you should maintain versions of server's copy of web.config in SVN too. We usually rename the production web.config to web.config.prod (a copy for each of the environments) and have the build tool pick the right file and rename it back to web.config while packaging for deployment.
svn rm --force web.config
svn commit
Be careful to back up your local copy (of web.config) before doing this, since it will be deleted.
I have solved this issue using nant with ccnet. Following nant build script replaces web.test.config file with local web.config file;
<?xml version="1.0"?>
<project name="Project1" default="build">
<target name="init" depends="clean" />
<target name="clean" />
<target name="checkout"/>
<target name="compile"/>
<target name="deploy"/>
<target name="test"/>
<target name="inspect"/>
<target name="build" depends="init, checkout">
<call target="compile" />
<call target="inspect" />
<call target="test" />
<call target="deploy" />
</target>
<copy file="..\TestDeployments\Project1\Project1.Solution\Project1.Web.UI\web.Test.config"
tofile="..\TestDeployments\Project1\Project1.Solution\Project1.Web.UI\web.config"
overwrite="true"
/>
<delete file="..\TestDeployments\Project1\Project1.Solution\Project1.Web.UI\web.Test.config" />
</project>
NAnt Copy Task

Resources