locked
web.config transformations on build/debug RRS feed

  • Question

  • User1967045674 posted

    Hi!

    I really like the new transformation feature for the web.config. It seems to work when I do "Build deployment package" but not when I just want to locally start the debugging using the green arrow. It just uses the web.config without processing the Web.Debug.config. I can prove that because in web.config I have debug="false" with a transformation in Web.Debug.config so that it gets true but everytime VS asks if it should modify the web.config to enable debugging which it should've done automatically with the following transformation:

    <?xml version="1.0"?>
    <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <system.web>
    <compilation debug="true" xdt:Transform="SetAttributes(debug)" />
    </system.web>
    </configuration>


    Am I missing something here? I used to work with NAnt to modify/create the web.config as a pre-build event but I thought that I wouldn't need it anymore. Am I wrong? The project is a freshly created asp.net mvc 2 web application.


    Thanks for your time!

    neo

    Wednesday, March 3, 2010 9:48 AM

Answers

  • User1291151714 posted

    Neo,

         The web.debug.config or web.release.config are only consumed by web deployment to transform web.config, say "Build deployment package" or "Publish". Regular build/debug doesn't invoke transform.

         Hope it helps.

                                  yugang

                                  microsoft visual web development team

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, March 5, 2010 12:42 PM
  • User1291151714 posted

    You are welcome.

    The web.config transform is implemented through a msbuild target. Currently only the web deployment feature invokes this specfic target. 

    Regular debugging invokes "build" only, but won't invoke the transform.  So you should either have an existing web.config defined or generate it through wiring up the build event like you did.  Dependent config files, such as "web.debug.config" or "web.release.config", are only used by deployment as a template to transform the original web.config . They are not involved in the debugging story.

    If I understand correctly, you want to have web.config  transform wired up on debugging? Currently, no, it is not supported, but we certainly will visit this for the next release of VS.  I did hear some similar feedback on this.

    For now, you can continue use your existing logic.

    Just in case you are interested, you can find the target definition of web.config transform at %Program Files%\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets, the target is "TransformWebConfig".

    Hope it helps. Please let me know whether or not this addresses your question.

                    Yugang

                    Microsoft visual web development team 

     

     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, March 5, 2010 4:53 PM

All replies

  • User1291151714 posted

    Neo,

         The web.debug.config or web.release.config are only consumed by web deployment to transform web.config, say "Build deployment package" or "Publish". Regular build/debug doesn't invoke transform.

         Hope it helps.

                                  yugang

                                  microsoft visual web development team

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, March 5, 2010 12:42 PM
  • User1967045674 posted

    Thanks for the explanation. I already guessed that after some more google searches. What I still don't understand is why it is the way it is. I mean, how should I use the web.config file for "regular" debugging? Should I change it manually everytime with the risk of accidently committing it to source control? I think it doesn't have any unexpected behaviour if it would do the same as in the deploy process. Instead it's more consistent. If there is a reason for that please tell me. Otherwise this could maybe be a feature for next versions?

    Thanks

    neo

    Friday, March 5, 2010 3:49 PM
  • User1291151714 posted

    You are welcome.

    The web.config transform is implemented through a msbuild target. Currently only the web deployment feature invokes this specfic target. 

    Regular debugging invokes "build" only, but won't invoke the transform.  So you should either have an existing web.config defined or generate it through wiring up the build event like you did.  Dependent config files, such as "web.debug.config" or "web.release.config", are only used by deployment as a template to transform the original web.config . They are not involved in the debugging story.

    If I understand correctly, you want to have web.config  transform wired up on debugging? Currently, no, it is not supported, but we certainly will visit this for the next release of VS.  I did hear some similar feedback on this.

    For now, you can continue use your existing logic.

    Just in case you are interested, you can find the target definition of web.config transform at %Program Files%\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets, the target is "TransformWebConfig".

    Hope it helps. Please let me know whether or not this addresses your question.

                    Yugang

                    Microsoft visual web development team 

     

     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, March 5, 2010 4:53 PM
  • User1291151714 posted

    Also one more thing, the web.config transform doesn't overwrite or generate a new web.config under your project  folder, rather a new one is created under "obj\<config name>\..." for deploy. We don't touch the original web.config because that has settings specfically for your local development machine, while transformation is used to transform some artifacts to hosting server environment such as new data connections pointing to live data server. 

    Hope it helps,

                          Yugang

                          Microsoft visual web development team

    Friday, March 5, 2010 5:16 PM
  • User1967045674 posted

    You say you don't touch the original web.config "because that has settings specifically for your local development machine". Although it is the right thing not to touch it, I don't think there should be settings for your specific local development machine in it because in the end the web.config should be under source control and be generic enough for everybody. Maybe it's better if I explain our structure a bit.

    We have several developers, say DevA, DevB, DevC. Each of those potentially needs a slightly different web.config file. Then we have a staging server and the live server, each needing its own web.config. Our sourcecode is on SVN, including web.config, web.staging.config and web.live.config. The difference between the final web.config's is mainly the database connection string but there could be other differences.

    The transformation feature as it is now works great for publishing to the staging and live server because it's actually deploying/publishing it using the transformation target.

    The problems are the development machines. After thinking about it I'm not sure anymore if my initial feature request is the right thing to do (transformations for local debugging) because that would implicitly say that one file per development machine would have to be put into source control where it may just not belong in an ideal world because it is too specific.

    Currently we are doing it like that: All development machines have the same local settings (database names etc.) which are put into the web.config file. So for local debugging it works just with that web.config without transformations. And for deploying the other config files are used for transformations as usual. This works for us but it may not work very well for larger projects. I'm not yet sure how the best way to handle it would be but I just wanted to explain the situation so you can think about it and maybe come up with new ideas.

    neo

    Friday, March 5, 2010 6:30 PM
  • User1291151714 posted

    When  the shared web.config will be checked into source control, it should avoid having machine specific settings in it as this will break team development. I agree with you on this one.

    Not sure the detail of your statement of "This works for us but it may not work very well for larger projects". I guess, maybe you don't like the fact that different developers might have to duplicate the web.config file so they can modify couple of config artifacts to fit their specific dev environemnt for example, mail alias on sending errors, url for the service reference. So the ideal approach would be to have a root web.config defining any firm settings and then each developer uses web.config transformation to add their own for the purpose of local debugging or just running the webs? Is this your concern?

    Thanks.

             yugang wang

             Microsoft visual web development team 

    Monday, March 8, 2010 3:35 PM
  • User1967045674 posted

    That's exactly what I meant. I could imagine the following for an ideal web.config management:

    1. As you said, there should be a root/generic web.config which doesn't contain machine specific settings. This file is in source control.

    2. For every deployment/publish target there should be a web.*.config transformation file. Depending on the company policy this could/should also be in source control. (Sometimes maybe not if sensitive passwords etc. have to be in there)

    3. Every developer has his own web.*.config transformation file adapted for his local debugging environment. This file should be in the same folder as the others from step 2 to avoid confusion. And these should be excluded from source control via svn:ignore or whatever.


    As I'm fairly new to C#/ASP.NET and the Visual Studio IDE I wondered about one thing which is in kind of conflict to excluding files for source control like in step 3. I saw that every file in a project is actually referenced in the corresponding .csproj file. So when I create my own developer specific web.config transformation file which shouldn't be under source control, how do I actually do that as it changes the .csproj file which I have to commit for regular other changes/file additions? Obviously I cannot let a file reference being added to the .csproj when I don't commit the corresponding referenced file. I'm probably asking that in the wrong forum now but at least it's connected to the web.config issue.

    Kind regards,

    neo

    Monday, March 8, 2010 4:56 PM
  • User1291151714 posted

    Actually,  the individual transformation file owned by each developer doesn't need to be included in the project file. As long as it is physically under the project folder, it will be picked up by transformation.  This also means you need to keep the root web.config at checked out status so it can be overwritten before the app gets run.

    If you are interested in exploring the possiblities to wire it up for build/debug, please feel free to contact me at yugangw at microsoft dot com. I can loop in related feature owner to give you some detail advice. There are a couple of more things need to be plugged in though.

    Hope it helps

                      Yugang

                      Microsoft visual web development team

     

     

    Tuesday, March 9, 2010 4:29 PM
  • User1967045674 posted

    Thanks for your offer, I may come back to that.

    What do you mean with "This also means you need to keep the root web.config at checked out status so it can be overwritten before the app gets run."? Shouldn't the root web.config never be overwritten? Actually that's a weak point of my last post. Where should the transformed web.config be stored for local debugging? I cannot overwrite the existing root web.config without messing up with source control. A solution could be that you create the transformed web.config in a temporary folder somewhere on the system so you would tell the builder/debugger that it should use the temporary file instead of the web.config in the project dir. Is that in any way possible?


    project/web.config => root file

    project/web.staging.config => transformation file for deployment to staging server

    project/web.dev22.config => transformation file for local debugging -> excluded from source control

    C:/temp/1234567random.web.config => temporary file created for local debugging


    I think this is the cleanest way of handling non-deployment builds which use transformation files. What do you think about that?


    Kind Regards

    neo

    Tuesday, March 9, 2010 5:29 PM
  • User1291151714 posted

    When the web app gets run, the web.config under project root folder will be picked up by asp.net and I know unfortunately it is under source control . I certainly understand the cleanness coming with letting runtime use a transformed web.config from a temp folder; however, asp.net runtime doesn't know anything about vs projec structure and it is totaly based on directory structure.  Using alternate path might also break as a web.config under a subfolder expect to inherit settings from the upper level of directory.

    I don't think there is any easy way to alter the path for loading the web.config, but i will check out.

         Yugang

         Microsoft visual web development team  

    Tuesday, March 9, 2010 9:19 PM
  • User415541384 posted

    Well Guys..I have same problem. I want to override web.config at compile time and source control isn't a problem. You can easily exclude file from source control but it will stay as a project file..

    Open <projectname>.csproj.vspscc:

    "NUMBER_OF_EXCLUDED_FILES" = "1"

    "EXCLUDED_FILE0" = "web.config"

    Then i use this macros:

    if exist "$(ProjectDir)Web.$(ConfigurationName).config" (copy "$(ProjectDir)Web.$(ConfigurationName).config" "$(ProjectDir)Web.config").

    BUT i want to use much more effective config transformation then to just copy one 3 files into one. It needs to stay 3 different configurations.

    So is there any way to transform config file using msbuild on debuging?

     

     

     

    Friday, March 19, 2010 9:34 AM
  • User-1672068718 posted

    it is sad that build/debug do not support web.config transformation. at my workplace, developers do not have write permissions to QA or production servers. i think this is true for many larger IT teams. i hope someone can come up with a workaround soon.

    Friday, April 16, 2010 8:56 PM
  • User-599278165 posted

    I too am very interested in doing this. If anyone has figured out how and would share that would be greatly appreciated.

    Monday, May 17, 2010 1:23 PM
  • User-418455025 posted

    I thought we found a good way to handle this using the following attribute in the web.config

    <connectionStrings configSource ="connectionStrings.config">

    </connectionStrings>

    This allows us to put the developer specific configs in a separate file (that is not under source control).  The file checked into source control is the same for everyone and is void of connection strings.  Each developer has their own copy of "connectionStrings.config" which is not checked into source control.  


    However, when we try to run unit tests using this technique we get an error such that the unit test project can't find the configSource file.  But it works well otherwise.

    Wednesday, May 19, 2010 10:50 PM
  • User-599278165 posted

    That was how I previously did it. However that method gets pretty ungainly the more sections you replace with all of the different environments. With, dev, demo, stg, and prod environments alone I ended up having 8  files per environment. You have to have each configsource in its own file. Also there are other added drawbacks like the fact you can not use configsource on section groups. Also unless you specify it, changes to sub files in configsource files will not force a reload of that section into the main web.config which is cached into memory.

    I have also seen complete whole seperate config files that would copy over the main config during the pre-build event. This is also ungainly as you are forced to carry a complete config per environment. This method also has the drawback of changing the web.config each run so it makes placing the web.config under a source control repository detrimental with a multi person team.

    The solution that they came up with in .net 4.0 is actually quite great we just want it to work at debug time.

    I have been communicating with the engineers about this and they are mulling over the various issue that arise from dynamically changing the web.config at debug/run time. Most of the issues they are running into revolve around source control and the integration with all of the designers in the IDE.

    Wednesday, May 19, 2010 11:08 PM
  • User939327180 posted

    Hi Tim,

    Not sure if you are still interested in a solution. I spent many hours chasing my tail on google, etc. on this. Anyway, the links that helped me the most were: http://stackoverflow.com/questions/1085293/two-visual-studio-post-build-event-questions-and-msbuild and http://stackoverflow.com/questions/2905151/msbuild-script-and-vs2010-publish-apply-web-config-transform. These gave me the clue I needed.

     

    I don't mess with MSBUILD that much but my solution was to add a custom target to the XXX.Web.csproj that did the transform and then add a custom "Post build" event to the XXX.Web.csproj that invoked MSBUILD (to perform the transform) and an XCOPY to copy the transformed web.config over the original. One side effect is that, as we have TFS, it always contains the last web.config that was transformed which can be a bit usettling (you keep thinking one of your other developers has overwritten your settings - which, in a sense, they have ;-)....but, of course, your settings are in the web.xxxxxx.config you use in the transform. Okay, enough explanation.

    Here's what you do: Copy and paste this into you XXXX.Web.csproj just above the commented out "Target Name="BeforeBuild" element...

    <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
      <Target Name="Transform">
        <MakeDir Directories="obj\$(Configuration)" Condition="!Exists('obj\$(Configuration)')" />
        <TransformXml Source="Web.Config" Transform="Web.$(Configuration).config" Destination="obj\$(Configuration)\Web.config" StackTrace="true" />
      </Target>
      <Target Name="AfterBuild">
      </Target>
     
    Next, go to project properties and click on 'Post Build' event. Copy and paste: 
    $(MSBUILDBINPATH)\msbuild $(ProjectPath) /t:Transform /p:Configuration=$(ConfigurationName);Platform=AnyCPU
    xcopy "$(ProjectDir)obj\$(ConfigurationName)\Web.Config" $(ProjectDir). /F /R /Y
    That's it. On the next build of your xxx.web.config, the post build will run the custom target and generate transformed web.config. The XCOPY will overwrite the existing.


     

    Sunday, October 17, 2010 12:34 AM
  • User724410907 posted

    Too bad the transformations dont work when debugging. It could be very useful to support different configurations for different databases/webservices/smtpservers etc. It could also be useful to support different configurations for different users.

    The precense of the file Web.debug.config is misleading. It suggest transforming in a debug environment, which is only true when you deploy to a debug server... which nobody does.

    To prevent overwriting the original Web.config, we may need a root configuration file "Web.(default).config". Hope to see it in the next VS release.

    Wednesday, October 20, 2010 5:20 AM
  • User-1672068718 posted

    I followed your steps but got this error message when i build...

    Error 1 Only one project can be specified.

    Error 2 The command "C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild path_to_my_proj_file.csproj /t:Transform /p:Configuration=Release;Platform=AnyCPU
    xcopy "path_to_my_proj_folder\obj\Release\Web.Config" path_to_my_proj_folder\. /F /R /Y" exited with code 4. 

    I also have MSBuild Extension Pack 4.0 installed. My VS is 2010 with .NET 4.0.

     

    thank you in advance.

     

    Ray

    Hi Tim,

    Not sure if you are still interested in a solution. I spent many hours chasing my tail on google, etc. on this. Anyway, the links that helped me the most were: http://stackoverflow.com/questions/1085293/two-visual-studio-post-build-event-questions-and-msbuild and http://stackoverflow.com/questions/2905151/msbuild-script-and-vs2010-publish-apply-web-config-transform. These gave me the clue I needed.

     

    I don't mess with MSBUILD that much but my solution was to add a custom target to the XXX.Web.csproj that did the transform and then add a custom "Post build" event to the XXX.Web.csproj that invoked MSBUILD (to perform the transform) and an XCOPY to copy the transformed web.config over the original. One side effect is that, as we have TFS, it always contains the last web.config that was transformed which can be a bit usettling (you keep thinking one of your other developers has overwritten your settings - which, in a sense, they have ;-)....but, of course, your settings are in the web.xxxxxx.config you use in the transform. Okay, enough explanation.

    Here's what you do: Copy and paste this into you XXXX.Web.csproj just above the commented out "Target Name="BeforeBuild" element...

    1. <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />  
    2.   <Target Name="Transform">  
    3.     <MakeDir Directories="obj\$(Configuration)" Condition="!Exists('obj\$(Configuration)')" />  
    4.     <TransformXml Source="Web.Config" Transform="Web.$(Configuration).config" Destination="obj\$(Configuration)\Web.config" StackTrace="true" />  
    5.   </Target>  
    6.   <Target Name="AfterBuild">  
    7.   </Target>  
    <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
      <Target Name="Transform">
        <MakeDir Directories="obj\$(Configuration)" Condition="!Exists('obj\$(Configuration)')" />
        <TransformXml Source="Web.Config" Transform="Web.$(Configuration).config" Destination="obj\$(Configuration)\Web.config" StackTrace="true" />
      </Target>
      <Target Name="AfterBuild">
      </Target>
     
    1. Next, go to project properties and click on 'Post Build' event. Copy and paste:   
    Next, go to project properties and click on 'Post Build' event. Copy and paste: 
    1. $(MSBUILDBINPATH)\msbuild $(ProjectPath) /t:Transform /p:Configuration=$(ConfigurationName);Platform=AnyCPU<BR>xcopy "$(ProjectDir)obj\$(ConfigurationName)\Web.Config" $(ProjectDir). /F /R /Y  
    $(MSBUILDBINPATH)\msbuild $(ProjectPath) /t:Transform /p:Configuration=$(ConfigurationName);Platform=AnyCPU
    xcopy "$(ProjectDir)obj\$(ConfigurationName)\Web.Config" $(ProjectDir). /F /R /Y
    1. That's it. On the next build of your xxx.web.config, the post build will run the custom target and generate transformed web.config. The XCOPY will overwrite the existing.  
    That's it. On the next build of your xxx.web.config, the post build will run the custom target and generate transformed web.config. The XCOPY will overwrite the existing.


     

    Thursday, October 21, 2010 7:58 PM
  • User939327180 posted

    Hi Ray,

    Probably, you need to quote the ProjectPath argument to the msbuild like:

    $(MSBUILDBINPATH)\msbuild --->"$(ProjectPath)"<----- /t:Transform /p:Configuration=$(ConfigurationName);Platform=AnyCPU

    you probably have spaces in your path to your .csproj.

     

    Friday, October 22, 2010 3:07 AM
  • User-1672068718 posted

    That is the problem. It also caused the second error.

    Thanks a lot.

    Ray

    Friday, October 22, 2010 12:17 PM
  • User-1153052533 posted

    It works like a charm, finally there is a solution.

    I just had to insert an "enter" or <br> (as you would say in HTML) before the xcopy call in :

     

    "C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild path_to_my_proj_file.csproj /t:Transform /p:Configuration=Release;Platform=AnyCPU xcopy "path_to_my_proj_folder\obj\Release\Web.Config" path_to_my_proj_folder\. /F /R /Y"

    (as you might see above that is missing a must look like below)

    this works:

    "C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild path_to_my_proj_file.csproj /t:Transform /p:Configuration=Release;Platform=AnyCPU

    xcopy "path_to_my_proj_folder\obj\Release\Web.Config" path_to_my_proj_folder\. /F /R /Y"

     

    Thanks a lot cmac3095 !!

    cheers

    christopher (MSFT)

    Tuesday, August 6, 2013 12:32 PM