Use multiple environments in .NET Framework 4.7.2 - asp.net

I have .NET Framework 4.7.2 project that uses for a azure app service that uses for API calls.
I want to use a different appsettings.json for each environment, I have multiple environments (production, pre-production and more...)
I saw this docs: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-3.1
But I didn't find something similar that works with .NET Framework.
How should I do it?

I don't think there's a simple/supported way of getting the settings filename override functionality that NET core has for .Net Framework because it doesn't have or use environment variables and projects/executables in the same way.
But there is a library called Slow Cheetah that seems to do this, which allows you to automatically transform your app.config (or any file) when you press F5 in Visual Studio
I ended up using a single App.config file with different keys - see below.
From here, you'll just need to work out your own trigger for determining your Dev/Prod etc environment - probably a build step.
(In my case, I had a ClickOnce app that was either published/prod or not/dev - so this part was easy)
<connectionStrings>
<add name="Dev"
connectionString="..." />
<add name="Prod"
connectionString="..." />
</connectionStrings>

Related

Azure DevOps - How to Publish an ASP.NET application

I have an ASP.NET (4.7.2) app that successfully runs and starts on my machine. This app has a web.config file that contains the following:
Web.config
<appSettings>
<add key="username" value="someone#email.com" />
<add key="port" value="25" />
</appSettings>
These are the configuration values I want to use while working. However, when I deploy the app to my Azure App Service for test purposes, I want to change the port value. For that reason, I've added a config transform named "Web.Test.config" with the following:
Web.Test.config
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add key="port" value="58" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
</appSettings>
</configuration>
Unfortunately, it doesn't seem like the transform is happening. I've ready that the transforms only happen during "publishing". At this time, I'm deploying via an Azure DevOps Pipeline that includes the following tasks:
NuGet
Restores the packages based on the .sln file
MSBuild
Builds the .csproj that defines my ASP.NET app. The "Configuration" property is set to "Test".
Azure App Service Deploy
Attempts to deploy the ASP.NET app as a "Web App on Windows" to my deployment slot. The "Package or folder" is set to MyAspNetApp. The
While this build pipeline successfully runs, the configuration transforms do not seem to be taking effect. How do I do a "publish" via an Azure DevOps Build Pipeline to an Azure App Service so that my config transformations will be generated.
For App.Config or Web.Config (XML) file there are two options.
File Transform task suggested by #Jabberwocky in the comment.
Variable Substitution as per below image in the release pipeline.
Sample XML variable substitution
For modern .NET apps where we use json configuration, variable substitution is the only way. Even though File Transform task promises to work for both it is not clear as per this thread
For JSON variables, you have to enter the full path hierarchy like this
Sample JSON variable substitution
How do I do a "publish" via an Azure DevOps Build Pipeline to an Azure App Service so that my config transformations will be generated.
First, we need to make sure the web.*.config files are included in the build output and the file is transformed correctly. Check it locally first.
Besides, the following steps should help:
Remove the nesting of the web.dev/stest/atest/prod.config files
either by removing the element in csproj, a nesting
add-on for VS or the File Nesting context menu item in VS 2017
A note from the documentation stated XML transformation notes that:
By default, MSBuild applies the transformation as it generates the web
package if the element is already present in the
transform file in the *.csproj file. In such cases, the Azure App
Service Deploy task will fail because there is no further
transformation applied on the Web.config file. Therefore, it is
recommended that the element is removed from all the
transform files to disable any build-time configuration when using XML
transformation.
Make sure that the *.config files have the 'Copy to Output Directory'
property set to if newer or always
Build the solution locally and check the contents of bin\release
folder and make sure the web.*.config files are included
Run a build in VSTS and make sure the web.*.config files are included
in the zipped package
Check the checkbox XML transformation on the Azure App Service Deploy task:
There is a great document about how to Using XML Transformations when deploying to Azure App Service using VSTS, you can check it for some more details.
BTW, since you just need to change the port value, you can use the option XML variable substitution on the the Azure App Service Deploy task.
Ticket for details: How to transform Web.Config file 'Properly' with VSTS!
Hope this helps.

MS Web Deploy Package ignoring databases when using connectionstring configsource

I am having a problem with Web Deploy packages recognizing SQL. I am using Visual Studio 2015, SQL Server 2014, SSDT Database Project. The workflow is, create a MVC project, create a Database project, and use the Web Deploy Package to run SQL queries on the DB project. I plan to Publish the MVC project into a web deploy package and add queries to the deployment as part of the package. (I am not trying DACPACs at the moment because I ran into issues where they were not including pre and post deployment scripts in them when using Web Deploy Tool).
The problem happens when publishing a web deploy package using the connection string below.
<connectionStrings configSource="connectionsettings.config">
That in the web.config prevents web deploy from detecting a database to add to the web package for web deploy packaging.
deloy package missing database
Whenever I change to a normal connection string, even something as simple as this:
<connectionStrings>
<add name="Default" connectionString="" providerName="System.Data.SqlClient" />
Then web deployment package works and you get the proper UI.
deloy package working
Anyone know how to get the database to show up using a configsource in the web.config connectionstrings? As an alternative, I was looking into getting parameters.xml to replace the blank connection string to include the configSource above, but have had no luck.
The idea was to remove the Default connection and replace it with the config source. Removing the default connection works but the configSource does not.
<parameter name="RemoveConnectionString" defaultValue="">
<parameterValidation kind="AllowEmpty" />
<parameterEntry kind="XmlFile"
scope="Web\.config$"
match="//configuration/connectionStrings/add[#name='Default']" />
</parameter>
<parameter name="AddConfigSource" defaultValue="connectionsettings.config">
<parameterEntry kind="XmlFile"
scope="\\web.config$"
match="/configuration/connectionStrings/#configSource" />
</parameter>
Web Deploy Package seems undeveloped for SQL, but is there a fix for my issue or a better way to do an all-in-one deploy for IIS & SQL?
Use WebDeploy Parameterization to manually create parameters for the separate config file.
Skip down to "Step 3 - Create a parameter file" in the following link:
http://www.iis.net/learn/publish/using-web-deploy/web-deploy-parameterization
This may also be helpful:
http://www.dotnetcatch.com/2014/09/08/parameterizationpreview-visual-studio-extension/

Web.config Build vs Release transform not working

I have an ASP.NET Web Application project that connects to a remote database via the Entity Framework. During debugging (eg running the project on my local computer), the IP address to the database is different than during release (eg after uploading the project to my webserver and running it from the browser). Until now I have always manually changed the database connection string in the Web.config file to switch between the two (basically I had to connection strings, one named 'Debug' and one 'Release' and I just swapped around the names whenever I deployed).
Now I just noticed that it should be possible to let this happen automatically via the Web.config Transformation Syntax where you put the modified connection string in the Web.Release.config version and it should then use that when the DLL is built under Release configuration.
However it does not seem to work for me...
Here is the relevant part of my regular Web.config file (which holds the Debug connection string for local usage):
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<!-- Debug connection string. Release connection string is in Web.Release.config file -->
<add name="DatabaseEntities" connectionString="A" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
Here is the Web.Release.config file, which according to the examples should replace the 'DatabaseEntities' connection string "A" with "B" if the DLL is under Release mode:
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!-- Replace the DatabaseEntities connection string with the Release version (local IP address) -->
<connectionStrings>
<add name="DatabaseEntities"
connectionString="B"
xdt:Transform="Replace" xdt:Locator="Match(name)"/>
</connectionStrings>
</configuration>
(Obviously "A" and "B" are just place-holders for my real connection strings)
When I debug the application (e.g. just press F5) the default Web.config is used and I can access the database. I then change the build configuration to Release via the Configuration Manager. All the projects in the solution are set to Release configuration. Then I Build the solution (just via Build or even via a complete rebuild (e.g. Clean, Rebuild)). I upload the newly built DLLs to the webserver, as well as the Web.config and Web.Release.config files, and when I try to access the database I am unable, it is still trying to access the database via the debug IP address and hence cannot find it...
It seems the Web.Release.config file is completely ignored, or at least the connection string is not being replaced.
What am I doing wrong? Is the transformation syntax wrong? Am I not building the application under Release mode correctly?
Then I Build the solution (just via Build or even via a complete
rebuild (e.g. Clean, Rebuild)). I upload the newly built DLLs to the
webserver, as well as the Web.config and Web.Release.config files
There is your error: Web config transforms won't work for your local environment, if you simply build. You need to publish.
Your deployment process seems weird: You are only copying DLLs, Web.config and web.Release.config. To me it seems, that you copy your source code and not a compiled application. A published WebApplication doesn't contain a web.release.config.
You should publish your project (rightclick on your WebApplication -> Publish) to your local filesystem and copy the files from there, or use another deployment method of your choice.
2 years ago I wrote an article about web.config transforms. It gives you a step-by-step tutorial for VS 2010 (The publish dialog changed in VS 2012): http://www.tomot.de/en-us/article/5/asp.net/how-to-use-web.config-transforms-to-replace-appsettings-and-connectionstrings
Inside your csproj file, you can add an action to execute before every build and perform the web.config transformations:
<Target Name="BeforeBuild">
<TransformXml Source="web.config" Transform="web.$(Configuration).config" Destination="web.config" />
</Target>
You can try the Slow Cheetah plugin:
http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5
This will let you see the transformations 'live' by giving you an extra context menu option. Right-click and choose Preview Transform to see the transformation without having to do a build. Its also really handy for implementing app.config transformations
I thought transformation is only done when you publish the site/app.
It is not done when building an application. The latter would constantly change the web.config under source control (which would be a real hassle)
If it's only connections strings that are not overwritten during web.config transformation, then this is what I did:
I cleared the "Use this connection string at runtime" check-box in the "Settings" section of "Publish Web" wizard. This setting was overwriting web.config transformation of the connection string.
It's pretty flexible, you should be able to make a few tweaks to apply custom transforms on build (and without having to publish)
We implemented this in our (Windows Service) project, applying transforms on build
You will need to modify your project file and add something similar to below
Here we're telling msbuild to apply transform after finish compiling, but only if condition is true (see https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-conditions?view=vs-2017)
Notice we are using an build prop (self defined msbuild prop) "Env", e.g. msbuild ... /p:Env=Prod would result in App.Prod.config
<UsingTask TaskName="TransformXml" AssemblyFile="C:\Some\Path\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterCompile" Condition="Exists('some condition')">
<!--Generate transformed app config in the intermediate directory-->
<TransformXml Source="App.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="App.$(Env).config" />
<!--Force build process to use the transformed configuration file from now on.-->
<ItemGroup>
<AppConfigWithTargetPath Remove="App.config" />
<AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
<TargetPath>$(TargetFileName).config</TargetPath>
</AppConfigWithTargetPath>
</ItemGroup>
</Target>

Web config setting for deployment

In my web.config file, I have a connection string to connect my development database.
<connectionStrings>
<add name="MembershipDB" connectionString="Data Source=DebugSQL;Initial Catalog=PortalAccess;Integrated Security=True;Application" providerName="System.Data.SqlClient"/>
When I publish the web site to my production server, I just change the Data Source name.
When I test it, then I switch it again, is it stupid?
This is quite a common approach and can work well.
Obviously you can run into problems if you get the details wrong while maintaining it by hand this way.
You could also have a look into web.config transformations: This is a way of writing a main web.config file and then writing separate files that change the original depending on the build configuration you run.
Some resources:
Related question on StackOverflow;
Asp.Net tutorial;
MSDN Video for VS 2010.

Compile Time DEFINEs in an ASP.NET Web Deployment Project

My environment is Visual Studio 2005. My specific problem is that I want to define TRACE.
I have a Web Site Project that send trace messages when run out of the ASP.NET Development Server thanks to defining it in the system.codedom element of the web.config.
When I deploy to IIS, I do so via a web deployment project. So the site is precompiled. Naturally, these entries serve no purpose on a compiled website.
My question is how do I define TRACE in the web deployment project?
The visual Studio IDE does not allow you to set compile time constants in web deployment projects as far as I can tell. However, since a .wdproj file is just an msbuild file, you can edit it with a text editor. You need to add a element to the sections as illustrated in the screen shot in the provided link.
I cannot change the link to an image since new users apparently can't add images:
Annotated screenshot of .wdproj in a text editor http://img140.imageshack.us/img140/1719/deploymentproject.png
There is no equivalent to #defines in C#. That said, it sounds like you want to use conditional tracing, which is easily accomplished. If you have diagnostic code throughout your project but want to define it, use the built in trace functionality, for example
System.Diagnostics.Trace.WriteLine("Some debug output");
Then, in your webconfig, you can configure it on/off using
<configuration>
<system.web>
<trace enabled="true" requestLimit="40" localOnly="false"/>
</system.web>
</configuration>
More info here

Resources