MSDeploy to multiple servers - asp.net

I am looking for a way to deploy to multiple different environments.
ie, dev, uat, prod1, and prod2 servers
I am under the impression msdeploy could work for this. Currently we have something that deploys using a command like
"C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe" -verb:sync -source:contentPath="D:\sourcepath" -dest:contentPath="D:\destpath", computerName=PRODSERVER1
"C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe" -verb:sync -source:contentPath="D:\sourcepath" -dest:contentPath="D:\destpath", computerName=PRODSERVER2
This would work, but in the application I'm developing that needs deploying has a database connection involved, which needs to be changed per environment.
<connectionStrings>
<add name="DEVServer" connectionString="Data Source=DEVServer\SQLinstance;Initial Catalog=DBNAME;User ID=sqluser;Password=sqlpassword" providerName="System.Data.SqlClient" />
</connectionStrings>
Also, since this is a WCF service I have an Identity for the endpoint that would need to be changed per environment as well
<identity>
<dns value="DEVServer" />
</identity>
Is there a way to parameterize this? Should I set up multiple web.config files? What is the easiest route to go about this?

Assuming you are using Visual Studio 2010 or 2012, you can set up a publish profile for each environment and put the database connection string in that, set up a Web.config transform for each publish profile to make the endpoint changes, and you can deploy using MSBuild from the command line instead of msdeploy directly.
For details on how to set up publish profiles, see http://msdn.microsoft.com/en-us/library/dd465337.aspx
For Web.config transform examples, see http://www.asp.net/web-forms/tutorials/deployment/deployment-to-a-hosting-provider/deployment-to-a-hosting-provider-web-config-file-transformations-3-of-12
On publishing from the command line, the format would be like the following for publishing a solution:
msbuild path\to\solution.sln /p:DeployOnBuild=true /p:PublishProfile=[nameofprofile] /p:Password=[password]
To publish a project rather than a solution, specify the .csproj/.vbproj file and add /p:VisualStudioVersion=11.0 for VS 2012 (10.0 for VS 2010).

Related

Use multiple environments in .NET Framework 4.7.2

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>

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/

Referenced project app.config transform with SlowCheetah

I have a ASP.NET MVC 4 web project
WebUI
that references a ASP.NET 4 Code Library
DAL
The Code Library has a reference to the SlowCheetah 2.5.5 NuGet package and is setup with several transformations for it's App.Config.
The WebUI is using the normal Web.Config transformations but I have also added a reference to SlowCheetah as a test for my problem but it didn't change my issue.
When I publish using
MS Web Deploy
in Visual Studio 2012 or when I publish straight to
File System
using a QA configuration the correct Web.QA.config is put in the root of my website, however the referenced class library configuration is not working, I get a sql connection error on the home page which alerts me that the correct App.Config transformation is most likely not being used for the referenced DAL project.
I thought this would be a .dll.config file in the bin folder for the WebUI, but I am not too sure as I have this working on another web server where I manually changed the default App.Config and Web.Config files and there is no .dll.config file present in the root bin directory of the website.
Anyone know how to get this working?
UPDATE:
Examples below:
DAL Code Library project App.Config
<configuration>
<configSections>
</configSections>
<connectionStrings>
<add name="DAL.Properties.Settings.DefaultConnection" connectionString="Data Source=(local);Initial Catalog=MyDB;Integrated Security=True;" />
</connectionStrings>
</configuration>
Part of Web.Config from my WebUI project
<connectionStrings>
<add name="WebUI.Properties.Settings.DefaultConnection" connectionString="Data Source=(local);Initial Catalog=MyDB;Integrated Security=True;" />
</connectionStrings>
I use a Settings.settings file for each project.
How can I merge the App.Config connection into my Web.Config so that it is transformed during publishing? preferably I would want it to just use the one connection when publishing to the web.
At the moment the DAL referenced project works on the web application if I set the app.config correctly (which only makes some sense to me since its a referenced .dll).
Does adding this DAL.Properties.Settings.DefaultConnection connection to my web.config replace the one the DAL is using?
All of your settings for the web application will come from the web.config file - the app.config won't be used or deployed with the web app. Most likely, that config is there because you are using Entity Framework and that's where the EDMX functionality stores it's connection string. If you put the connection string in the web.config (and use the appropriate config transformations), you should be good.

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>

Resources