slow-cheetah
slow-cheetah copied to clipboard
SlowCheetah not transforming on F5 for web project
Hello,
I have made a post about this issue on StackOverflow: https://stackoverflow.com/questions/44420592/slowcheetah-not-transforming-on-f5-debug
Basically whenever I try to debug (F5) my app and select "Test" build configuration the config transforms don't get applied and I end up debugging with the settings in my regular Web.config vs. the intended Web.Test.Config settings.
My best understanding of what SlowCheetah does was that you can create a custom build configuration, add a config file for it, select that configuration and then hit F5 and voila config transform gets applied and I am debugging my app with "Test" configuration settings vs. regular Debug setting.
Running VS2015 Update 3 with a fresh install of 3.0.61 and have installed the latest VS extension. Am I not understanding something about how SlowCheetah works?
Thanks.
The transformation does indeed get applied to the config file (you can verify this by looking at the web.config file in the output folder). Unfortunately, web projects don't use the configuration file in the output folder, it uses the in-place web.config (the original one in your project tree). This is different from other project types that use the app.config on the output folder. Since the SlowCheetah transformation process does not alter project files itself (only output files), transformations won't work on F5 for web projects, only on publish.
Thanks for the reply Davi.. I must say that this kind of sucks that it doesn't do it for web apps because it would be so super helpful to be able pick a configuration and start debugging with those configuration settings...are there any plans to make it work as such? ..It does perform correctly on publish. Would you recommend (and I will research it) of the best approach to make it work like I want it to?
Thanks again.
It's a little more complicated for web projects since they already start off with a base file and transformation files. XML transformations already exist for these projects on publish. Transforming the original file on build would result in changes for users that already use it as their base config.
One option that is available is to have Web.Base.config
as the base configuration and then have Web.{Configuration}.config
as the transformation files. Then, on F5, the transformation output would override Web.config
in the project folder.
If you have knowledge of MSBuild targets, you can attempt to do this by altering the ScAppConfigName
property to Web.Base.config
(don't forget to create transforms for this file, i.e Web.Base.{Configuration}.Debug
) and then creating a target to copy the transformed Web.Base.Config
file in the output to the original location of web.config
.
As for including this behavior (with Web.Base.Config) in SlowCheetah, what would you think of it being an opt-in behavior that is turned off by default? This would be ideal so no one's experience is changed unless they want to.
I also think it would be ideal to have an opt-in behavior that comes with SlowCheetah for transforming the base Web.Base.Config to Web.Debug.Config / Web.Release.Config / Web.SomeCustomConfig.Config based on whatever's selected when one hits F5. Everything would 'derive' from Web.Base.Config by default, and then transform accordingly. This would also be such a great time saver and reduce inter-config copy/paste errors during the process of debugging different configurations. This sounds like a perfect solution to me:)
I am not sure if we want to support this behavior officially in slow-cheetah. It is only a partial solution and introduces other issues such as #64
@jviau I just had same issue as @WebDev64. I understand that described above behavior is working for web based projects and default and there isn't way to change it right now. I'd like to create issue with proposal of changing this behavior, but I'm unsure where I should create it. Is it VS or IIS Express related issue? I think it's reasonable to have same behavior for all types of projects. Don't You agree?
Here's what we do. It's not hard to set up but not intuitive or well documented.
- Create web.config.template. No build action, do not copy. Copy-paste your web.config contents here. (This is an arbitrary name, no black magic.)
- Right-click and select "Add Transform". This will get you files like Web.config.Debug.template and Web.config.Release.template. Add your transforms here.
- Unload your project (right-click on project, select "Unload Project")
- Open the .csproj file (right-click on closed project, select "Edit
.csproj" - Add the XML below to the bottom of the file (just before </Project>)
- Build the project. This should create a web.config file, but you still need to add it to the project.
- Click "Show All Files"
- Right-click the new web.config that was created and select "Include in Project"
- Delete and transform files that were added automatically under web.config
<Target Name="BeforeBuild">
<TransformXml Source="Web.config.template" Destination="Web.config" Transform="Web.config.$(Configuration).template" />
</Target>
Now when you build, you'll get a shiny new web.config that is the result of the transformation.
Be sure to add the .template files to source control, and exclude the actual web.config. I also put a big warning at the top of Web.config.template to only edit the .template files, not the actual web.config, or your changes will be overwritten.
@nlaslett Unfortunately I think that solution would fail if you're publishing the website through Visual Studio Team Services. There's a build step that goes through all the files referenced in Solution Explorer before the build and if any of them are not on the file system it crashes out with a "file not found" error. Very annoying but there you are.
I solved this simply adding this to the .csproj file:
<Target Name="BeforeBuild"> <TransformXml Source="Web.config" Destination="$(OutputPath)\Web.config" Transform="Web.$(Configuration).config" /> </Target>
Hope it helps.
@Laperuta this doesn't work for me, the transformation is still not applied
A major drawback of the Web.Base.config / template approach is that often when installing NuGet packages, changes are applied to the Web.config file, and not to the Web.Base.config file. Build once and these changes are now gone, you probably never even noticed a NuGet package tried to add them. And then you wonder why something doesn't work.
Yeah. I don't understand why Microsoft didn't simply allow you to write a Web.config in the bin directory that would override the main Web.config file. Then you could apply your XSLT transformations to that before debugging, and it would solve a lot of problems.
@jez9999 I was just thinking the same thing. This difference between web projects and regular applications is exactly why SlowCheetah doesn't work for web projects, it relies on having an "output config" in the bin folder.
~~@Laperuta:~~
~~I solved this simply adding this to the .csproj file:
<Target Name="BeforeBuild"> <TransformXml Source="Web.config" Destination="$(OutputPath)\Web.config" Transform="Web.$(Configuration).config" /> </Target>
~~
~~You are replacing the Web.config itself with a new Web.config. Doing this, you won't be able to properly use Insert
in your transformations. If you do, you'll run in to issues after transforming twice, because now your Insert
happened twice. Also, this is not a suitable approach if you want to put developer-specific or sensitive data in a separate (non-committed) transformation.~~
Never mind, I missed that $(OutputPath)
in there... this won't work. See my suggestions below.
@RudeySH I just posted an issue about it: https://github.com/aspnet/KestrelHttpServer/issues/3038
Another workaround for transforming Web.config files for debugging purposes is doing this.
<TransformXml Source="Web.config" Destination="$(OutputPath)\Web.config" Transform="Web.$(Configuration).config" />
(Note that this creates a new Web.config file in your bin folder. This doesn't use the ProjectName.dll.config file that already exists in your bin folder.)
And do this in your Application_Start
:
var transformed = WebConfigurationManager.OpenWebConfiguration("~/bin"); // this will read the new Web.config
foreach (KeyValueConfigurationElement setting in transformed.AppSettings.Settings)
{
WebConfigurationManager.AppSettings.Set(setting.Key, setting.Value);
}
This method avoids the drawbacks of the Web.Base.config method. But it has it's own issues. You can't use xdt:Transform(Remove)
. You also can't use anything other than app settings in your transformation (so no connection strings).
A major drawback of the Web.Base.config / template approach is that often when installing NuGet packages, changes are applied to the Web.config file, and not to the Web.Base.config file. Build once and these changes are now gone, you probably never even noticed a NuGet package tried to add them. And then you wonder why something doesn't work.
Agreed, and it's bitten me before. I've soured on this approach, and now just try and avoid getting too tricky with web.config transforms. I'll usually have the dev connection strings in the main file and use the Release template for prod settings, which only get applied when I publish the site. If I need to test against prod I manually tweak the connection strings while testing.
Why would transforms kill off changes made to the base web config? You don't have to replace all appSettings, for instance - you can just match the ones you want to modify and replace them.
Why would transforms kill off changes made to the base web config? You don't have to replace all appSettings, for instance - you can just match the ones you want to modify and replace them.
The problem on a web project is your web.config is in the project root, not the bin folder. When you Publish it's not an issue: the transformed file becomes the new web.config in the publishing root. But when you just debug in place (F5), your original web.config (without the transformations) is what you're running on. (You do get the transformed file in the bin folder as {project}.dll.config, but that doesn't help any.)
My initial idea (which works) was to instead have a web.config.template file with build-specific transforms under that. Then, when you build (not publish) you generate a crisp new web.config in the web root. Change from Release to Debug? You get a new web.config with the right settings. Great, eh?
The problem is, as @RudeySH points out, is that some NuGET packages need to add or update entries in the web.config. So they do that, but they're updating the generated file, not the web.config.template. Then when you rebuild, you lose those changes. It's a real pain if you forget to manually copy those changes over (or don't notice).
I take back my original advice. Instead, make your base web.config with all your debug settings, and use the release transform file for production. Then, publish the project when you go to prod. (Yes, I've seen people "deploy" web projects by copying the project root...)
Just start it from the debugger folder and attach to process. It will load the transformed configuration and you will be able to debug it.
Microsoft wants to sell Azure Key Vault, that's why they don't allow simple local specific configurations like any other frameworks provide.