This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I use Web.debug.config in the built-in visual studio debugger server?
I want to use the Web.config transformation that works fine for publish also for debugging.
When I publish a web app, Visual Studio automatically transforms the Web.config based on my currenctbuild configuration.
How can I tell Visual Studio to do the same when I start debugging?
On debug start it simply uses the default Web.config without transformation.
Any idea?
OK, with the understanding that web.debug.config & web.release.config are for package/publish only. I have come up with a way in which to enable what you are trying to do. I've blogged about it at https://devblogs.microsoft.com/aspnet/asp-net-web-projects-web-debug-config-web-release-config/.
Here is the summary.
Now let’s see how we can enable what the question asker wants to do.
To recap, when he builds on a particular configuration he wants a specific transform to be applied to web.config. So obviously you do not want to maintain a web.config file, because it is going to be overwritten.
So what we need to do is to create a new file web.template.config, which is just a copy of web.config. Then just delete web.config by using Windows Explorer (don’t delete using Visual Studio because we do not want to delete it from the project).
Note: If you are using a source control provider which is integrated into Visual Studio then you probably want to delete web.config from source control.
Also with this we do not want to use web.debug.config or web.release.config because these already have a well defined role in the Web Publishing Pipeline so we do not want to disturb that. So instead we will create two new files, in the same folder as the project and web.template.config, web.dev.debug.config and web.dev.release.config.
The idea is that these will be the transforms applied when you debug, or run, your application from Visual Studio. Now we need to hook into the build/package/publish process to get this all wired up. With Web Application Projects (WAP) there is an extensibility point that you can create a project file in the same folder with the name {ProjectName}.wpp.targets where {ProjectName} is the name of the project. If this file is on disk in the same folder as the WAP then it will automatically be imported into the project file. So I have created this file. And I have placed the following content:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Make sure web.config will be there even for package/publish -->
<Target Name="CopyWebTemplateConfig" BeforeTargets="Build">
<Copy SourceFiles="web.template.config"
DestinationFiles="web.config"/>
</Target>
<PropertyGroup>
<PrepareForRunDependsOn>
$(PrepareForRunDependsOn);
UpdateWebConfigBeforeRun;
</PrepareForRunDependsOn>
</PropertyGroup>
<!-- This target will run right before you run your app in Visual Studio -->
<Target Name="UpdateWebConfigBeforeRun">
<Message Text="Configuration: $(Configuration): web.dev.$(Configuration).config"/>
<TransformXml Source="web.template.config"
Transform="web.dev.$(Configuration).config"
Destination="web.config" />
</Target>
<!-- Exclude the config template files from the created package -->
<Target Name="ExcludeCustomConfigTransformFiles" BeforeTargets="ExcludeFilesFromPackage">
<ItemGroup>
<ExcludeFromPackageFiles Include="web.template.config;web.dev.*.config"/>
</ItemGroup>
<Message Text="ExcludeFromPackageFiles: #(ExcludeFromPackageFiles)" Importance="high"/>
</Target>
</Project>
Let me explain this a bit. I have created the CopyWebTemplateConfig target which will always copy web.template.config to web.config on build, even if you are not debugging your application in Visual Studio.
This is needed because we still need to support the package/publish process of Visual Studio. Then I extended the property PrepareForRunDependsOn to include the UpdateWebConfigBeforeRun target. This property is used to identify the list of targets which needs to be executed before any managed project is run from Visual Studio.
In this target I am using the TransformXml task to transform web.template.config, using the correct web.dev.***.config file. After that your app starts up using the correct web.config based on your build configuration.
After that I have another target ExcludeCustomConfigTransformsFiles, which I inject into the package/publish process via the attribute BeforeTargets=”ExcludeFilesFromPackage”. This is needed because we do not want these files to be included when the application is packaged or published.
So that is really all there is to it.
To explain the package/publish process a bit more for this scenario. When you package/publish web.debug.config or web.release.config, depending on build configuration, will still be used. But ultimately the file that it is transforming is web.template.config, so you may have to adjust depending on what you have in that file. Questions/Comments?
Andrew is on the right path. When you are using this feature here is how it was designed to be used.
web.config
This is the config file which developers should use locally. Ideally you should get this to be standardized. For instance you could use localhost for DB strings, and what not. You should strive for this to work on dev machines without changes.
web.debug.config
This is the transform that is applied when you publish your application to the development staging environment. This would make changes to the web.config which are required for the target environment.
web.release.config
This is the transform that is applied when you publish your application to the "production" environment. Obviously you'll have to be careful with passwords depending on your application/team.
The problem with transforming the web.config that you are currently running is that a transform can perform destructive actions to the web.config. For example it may delete a attributes, delete elements, etc.
You could just use the 'default' web.config as your development/debugging version, and then the web.release.config would of course continue to be the release version, since its transforms are applied when you publish.
In your debug configuration, add a post-build step, and use it to replace/transform your web.config
Although I agree that the simplest approach is usually the best, I can easily imagine a circumstance where for some period of time you want to connect your IDE to a test database instead of your development database. Although you can specify the development connect strings in your default web.config file, it would be really nice to have a Web.Test.config file so that when you swap your build configuration to "Test", you would automatically get the new settings while still in your IDE.
The historical alternative is commenting out one set of connection strings for another, but these new config transforms held out the hope of finally putting a stake in the heart of that ugly practice. Although one default file for development and a transform for release may work much of the time, adding a post-build step to transform the web.config file is the more complete answer in my opinion.
Related
I have a web application in VS 2017 for which I've defined a publish profile which works, happily, deploying / publishing the website to a location on the file system.
I understood that this was possible as part of the regular build process, i.e. just building the solution in Visual Studio or TFS build - and that this was achievable with a section like this:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DeployOnBuild>True</DeployOnBuild>
<PublishProfile>ProfileName</PublishProfile>
</PropertyGroup>
However, this has no effect whatsoever, the build output log just shows the regular build happening and no attempt to publish.
Should this work as suggested in various answers on here and MSDN - and if so, what is wrong with the above?
(In case anybody is wondering, the reason for doing this is that a single solution being built by TFS cannot separately publish > 1 web application with separate publish profiles as required with the build definition MSBuildArguments setting).
I want to credit #Andy-MSFT who posted a very close answer, but in the end there were some vital details missing and some corrections required to make it work.
First off, the working solution was:
<Target Name="Deploy" AfterTargets="Build">
<MSBuild
Condition="'$(DeployOnBuild)'!='true' And '$(Configuration)|$(Platform)' == 'Release|AnyCPU'"
Projects="$(ProjectPath)"
Targets="WebPublish"
Properties="DeployOnBuild=true;PublishProfile=FolderProfile"/>
</Target>
The WebPublish target will only work on a TFS build server if the "Web Developer Tools" of Visual Studio (2017 in my case, as per the question) are installed. Note that the "Projects" attribute had to be set with $(ProjectPath) which is also different to Andy's answer and was also needed for this to work.
The DeployOnBuild property specifically was ignored when set statically in the project file. Apparently it is a special property that must be set globally on the commandline.
As a workaround, you could call MSBuild again to pass the property. See How to: Extend the Visual Studio Build Process
Open the .csproj file with text editor.
Add below snippet at the end, then save it.
<Target Name="AfterBuild">
<MSBuild Condition="'$(DeployOnBuild)'!='true'" Projects="$(MSBuildProjectFullPath)" Properties="DeployOnBuild=true;PublishProfile=YourPublishProfile;BuildingInsideVisualStudio=False"/>
</Target>
Below threads for your reference:
Publish WebDeploy Automatically with VS Build
Visual Studio 2013 Build and Publish
Does anyone understand Microsoft's idea of TransformXML and running a WebApp with transformed Web.config in Debug mode?!
It's simply so that IIS Express does not pick up transformed (TransformXML in PostBuild) Web.config files from the bin/ folder.
I have tried to copy my transformed Web.config (PostBuild):
Web.config => bin/Web.config
Web.config => bin/<AssemblyName>.dll.config
without success.
I have tried to create temporary files that are imported by "configSource" but they are not copied if not enlisted in the project.
I don't want to have my debug settings as default settings in the project (I'm reusing the transformations for App.config in WebJobs- and Integration tests projects in the same solution).
The proposed solutions of overwriting Web.config in the source folder are just not right.
Simply said: I just want the Web.config to be transformed and take it for a spin by hitting F5. That's it.
Does anyone know how to make IIS Express read the transformed bin/Web.config file when starting a Webapp in debug mode by hiting F5? Anyone knowing of any hidden tweaks for IIS Express to make it work the correct way?
Thanks for any solution on this.
Microsoft would be out of business by the end of the year if developers were able to bill them for all those lost hours of trying to get their non-scriptable non-logical solutions to work in reality.
I have a folder on my web application which is used to store user uploads, i.e. profile pictures, that sort of thing.
When I use WebDeploy, there is an option for "Leave extra files (Do not delete)" which when ticked makes sure that the profile pictures are not deleted.
What I am seeking is a way to ensure that even if that is unticked, a certain folder is safe from deletion. The reason for this being that I don't want another developer to accidentally disable the feature in future. Or me for that matter.
Any ideas? I have seen a few similar questions on here but nothing seems to be relevant to Visual Studio 2010, which is what I am using.
(I assume you're using publish profiles as per Visual Studio 2010 w/ the Azure SDK or Visual Studio 2012 RTM. If you're not, create an MSBuild file called ProjectName.wpp.targets in the project root and put content in that instead)
You can disable all forms of deletes by setting <SkipExtraFilesOnServer>true</SkipExtraFilesOnServer> in your publish profile (equivalent to the checkbox you mentioned).
To skip a particular directory, a comment on this question implies you can use the following syntax:
<ItemGroup>
<ExcludeFoldersFromDeployment Include="FolderName" />
</ItemGroup>
But I've never seen that before and haven't tested it. Failing that, you can specify an explicit skip rule. "FolderName" is being skipped here - keep in mind that AbsolutePath is a regex:
<MsDeploySkipRules Include="SkipFolderName">
<SkipAction>Delete</SkipAction>
<ObjectName>dirPath</ObjectName>
<AbsolutePath>FolderName$</AbsolutePath>
</MsDeploySkipRules>
NOTE: There are some scenarios in which skip rules don't work when using Visual Studio unless you also set UseMsDeployExe to true
You can set specific rules on the target machines using the msdeploy.exe.configsettings file, there is also a msdeploy.exe.configsettings.example file in the same folder. The file is located in %program files%\IIS\Microsoft Web Deploy - folder see Web Deploy Rules
You can set Rules and skipDirectives here and enable whether they are defaulted so you get your expected default behaviour.
I am currently attempting to use Visual Studio 2010 'Publish' and MSDeploy functionality to handle my web deployment needs but have run into a roadblock with regards to customizing the package depending on my build configuration.
I develop in a 32bit environment but need to create a release package for a 64bit environment, so in the 'Release' configuration I have a post build event that copies the 64bit version of a third-party dll into the bin directory overwriting the 32bit version. When I use the 'Publish' functionality, even though the correct 64bit dll is being copied to the bin directory, it doesn't get included in the package.
Is there a way to get the 'Publish' to include files that have been copied into the bin directory during a post build event?
I answered a similar but different question at How do you include additional files using VS2010 web deployment packages?.
In your scenario you are using post build event, I would recommend dropping the post build event and implement your actions using your own MSBuild targets instead of post build event. Below you'll find the text of the other answer.
From: How do you include additional files using VS2010 web deployment packages?
Great question. I just posted a very detailed blog entry about this at Web Deployment Tool (MSDeploy) : Build Package including extra files or excluding specific files.
Here is the synopsis. After including files, I show how to exclude files as well.
Including Extra Files
Including extra files into the package is a bit harder but still no bigee if you are comfortable with MSBuild, and if you are not then read this. In order to do this we need to hook into the part of the process that collects the files for packaging. The target we need to extend is called CopyAllFilesToSingleFolder. This target has a dependency property, PipelinePreDeployCopyAllFilesToOneFolderDependsOn, that we can tap into and inject our own target. So we will create a target named CustomCollectFiles and inject that into the process. We achieve this with the following (remember after the import statement).
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
This will add our target to the process, now we need to define the target itself. Let’s assume that you have a folder named Extra Files that sits 1 level above your web project. You want to include all of those files. Here is the CustomCollectFiles target and we discuss after that.
<Target Name="CustomCollectFiles">
<ItemGroup>
<_CustomFiles Include="..\Extra Files\**\*" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>Extra Files\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
Here what I did was create the item _CustomFiles and in the Include attribute told it to pick up all the files in that folder and any folder underneath it. Then I use this item to populate the FilesForPackagingFromProject item. This is the item that MSDeploy actually uses to add extra files. Also notice that I declared the metadata DestinationRelativePath value. This will determine the relative path that it will be placed in the package. I used the statement Extra Files%(RecursiveDir)%(Filename)%(Extension) here. What that is saying is to place it in the same relative location in the package as it is under the Extra Files folder.
Excluding files
If you open the project file of a web application created with VS 2010 towards the bottom of it you will find a line with.
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
BTW you can open the project file inside of VS. Right click on the project pick Unload Project. Then right click on the unloaded project and select Edit Project.
This statement will include all the targets and tasks that we need. Most of our customizations should be after that import, if you are not sure put if after! So if you have files to exclude there is an item name, ExcludeFromPackageFiles, that can be used to do so. For example let’s say that you have file named Sample.Debug.js which included in your web application but you want that file to be excluded from the created packages. You can place the snippet below after that import statement.
<ItemGroup>
<ExcludeFromPackageFiles Include="Sample.Debug.xml">
<FromTarget>Project</FromTarget>
</ExcludeFromPackageFiles>
</ItemGroup>
By declaring populating this item the files will automatically be excluded. Note the usage of the FromTarget metadata here. I will not get into that here, but you should know to always specify that.
I found a workaround for the problem by using the ExcludeFilesFromDeployment element within the project file. I got the idea from Web Deployment: Excluding Files and Folders
So if you need to package project files as they exist in your project directory after a successful build and associated post build steps then do the following.
Edit "Package/Publish Web" project settings and
select Items to deploy to be "All files in this project folder"
Unload the project
Right click on the unloaded project and select to edit the project config
Locate the PropertyGroup element associated to the configuration setting e.g. "Release"
Within the PropertyGroup element add in the following elements and exclude files and folders you don't want in the package
<ExcludeFilesFromDeployment>*.cs;**\.svn\**\*.*;Web.*.config;*.csproj*</ExcludeFilesFromDeployment>
<ExcludeFoldersFromDeployment>.svn;Controllers;BootstrapperTasks;Properties</ExcludeFoldersFromDeployment>
Save and reload your project
This solves my problem for the time being but if there is a better solution then please let me know, as this is not ideal due to the hackery involved, but then again perhaps this is an uncommon deployment scenario?
Select your files or folders and Change Build action as Content from Properties Window.
I know its a old question but none of these worked for me .
In 2017 VS I just right clicked on the extra folder to be published and select publish it worked.
Example:
Adding the bin folder (and it's contents) to the project caused the files to be copied to the publish output directory.
For me, my issue was that I needed to place a proprietary software license file in the bin/ folder, but did not want to copy it manually each deployment.
This was using Visual Studio 2015 Professional
I know this is an old conversation but I came upon it while trying to do the same thing and I thought it would be helpful to add what I found here.
Nearly all the articles about including extra files in your publication use this method of adding the CopyAllFilesToSingleFolderForPackageDependsOn or CopyAllFilesToSingleFolderForMSDeployDependsOn items in the PropertyGroup and they all same something like "I added this to the end of the file ..."
This is what I did and spent an afternoon trying to find why nothing was happening until I realised there was already a PropertyGroup section at the top of the file. When I put my CopyAllFilesToSingleFolderForPackageDependsOn into that section it worked fine.
Hope this saves someone time some day
I have an ASP.net Web Site Project (.net 3.5). Currently all of the non-code behind code files (including Linq2Sql stuff, data contexts, business logic, extension methods, etc) are located in the App_Code folder.
I am interested in introducing Unit Testing (using nunit) in at least some sections of the project moving forward. Any Unit Testing that I would be doing would need to have full access to all of the code that is currently located in the App_Code folder. I have done some initial reading so far, and the consensus seems to be:
This will not be possible given my current setup
Unit testing requires referencing classes that are part of a compiled dll, and a Web Site Project by definition only compiles at run time.
In order to proceed, I will need to either convert my entire project to a Web Application, or move all of the code that I would like to test (ie: the entire contents of App_Code) to a class library project and reference the class library project in the web site project. Either of these will provide access to the classes that I need in compiled dll format, which will allow me to Unit Test them.
Is this correct? Or is there another way that I can Unit Test without restructuring/refactoring my entire project?
My shop has finally worked through an answer for this for our MVC project. And I want to share it as I chased a lot of dead ends here on StackOverflow hearing a lot of people say it couldn't be done. We do it like this:
Open the MVC folder "as a website, from local iis" which gets intellisense and debugging working properly
Add a unit test project that lives in our source controlled directory
Add a pre-build step to the TEST project, since we can't add one to a project that is open as a website. Imagine website is \FooSite and
our test project is \FooSite.Tests. The compiled app code will end up
in FooSite.Tests\FooSite_Precompiled\bin.
*
<Target Name="BeforeBuild">
<AspNetCompiler VirtualPath="FooSite" TargetPath="$(ProjectDir)\FooSite_Precompiled" Force="true"
Debug="true" /> </Target>
Add a reference to the FooSite_Precompiled/bin/App_Code.dll in your test project.
Boom that's it. You can have your cake and eat it too. Every time you click Build in your solution you call the aspnet_compiler.ext tool
on your website csproj (which does still exist) which is able, unlike
MSBuild, to compile app_code, and the Debug="true" allows you step
into the app_code.dll code when debugging your unit test. And you
only need to Build when you're running updated unit tests. When
you're looking at the effects of your change on the page, you just
Change Code/Save/Refresh Page since the app_code folder dynamically
compiles when called from your web server.
Your conclusions seem correct. I would vote for moving functionality into one or several class library projects, since that may open the door for reusing the same functionality in other projects as well.
We have this issue at my company (My boss doesn't like DLLs, some rubbish about versioning...)
We have two ways round it that we use frequently:
1) Get the CI tool to do the unit testing: We use TeamCity which has a pretty tight NUnit integration, and our solution builds quick enough (and has few enough tests) for this to be a valid option.
2) Manually precompile and unit test the resulting binaries: It's perfectly possible to run the ASP.net compiler / MSBuild from the command line (as if you were doing a 'Publish' build) and just unit test the resulting binaries.
However, if you have the option of segregating the code into binaries (class libraries) or just using a web application, I'd suggest that as a better alternative.
Should anyone find themselves implementing Brian's solution, here's a Website.targets file you can include in unit testing solution. It (re)compiles website only when App_Code changes. Just add something like
<PropertyGroup>
<WebsiteName>MyWebsite</WebsiteName>
<WebsitePath>..</WebsitePath>
</PropertyGroup>
<Import Project="$(ProjectDir)\Website.targets" />
<Target Name="BeforeBuild" DependsOnTargets="CompileWebsite">
</Target>
to your .csproj, customizing WebsiteName and WebsitePath and you should be ready to go. Website.targets:
<?xml version="1.0" encoding="utf-8"?>
<!--
Target that compiles Website's App_Code to be used for testing
-->
<Project DefaultTargets="CompileWebsite" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<AppCodeFiles Include="$(WebsitePath)\$(WebsiteName)\App_Code\**\*.*" />
</ItemGroup>
<Target Name="CompileWebsite" Inputs="#(AppCodeFiles)" Outputs="$(ProjectDir)\PrecompiledWeb\bin\App_Code.dll">
<AspNetCompiler VirtualPath="$(WebsiteName)" PhysicalPath="$(WebsitePath)\$(WebsiteName)" TargetPath="$(ProjectDir)\PrecompiledWeb" Force="true" Debug="true" />
</Target>
<Target Name="CleanWebsite">
<RemoveDir Directories="$(WebsitePath)\$(WebsiteName)\PrecompiledWeb" />
</Target>
</Project>
It looks like this is possible whilst still using App_code, but I would either move this logic out to its own class library project or change the project type to Web Application, as Fredrik and Colin suggest.
I always create my own ASP.NET projects as Web Application projects not Websites.
And as the OP stated it's also possible to move to a Web App project, which i would say is cleaner as well, your pages can stay in the wep app project, you will have them in 1 DLL (testable). All your business logic etc. goes in a separate class library / libraries.
It is possible to unit test classes stored in the App_Code folder without converting your project to a Web App or moving your classes to a Class Library project.
All that is necessary is setting the code files' Build Actions to Compile. This will cause Debugging and Unit Testing your website to output a .dll file.
Now when you reference your website project from the unit test project, the classes in the app_code folder will be visible.
NOTE:
Setting your .cs files' Build Action to Compile will cause your website to generate a .dll file on debugging and unit-testing. The .dll file will cause problems when you debug your website because IIS will now find your code in two places, the bin and the App_Code folder and will not know which one to use. I currently just delete the .dll file when I want to debug.
I had to change Brian White's solution by adding the PhysicalPath attribute. In addition I am not using the Default Web Site and had to change the VirtualPath property to my website name.
<Target Name="BeforeBuild">
<AspNetCompiler VirtualPath="myIISsitename.com" PhysicalPath="$(SolutionDir)MySiteFolder" TargetPath="$(ProjectDir)\MySite_Precompiled" Force="true" Debug="true" />
</Target>
The resulting dll will be at MySite_Precompiled\App_Code.dll