Environment variables not being set when deploying to Azure Cloud Service via Visual Studio - node.js

Having a few issues with environment variables in Azure Cloud Services.
I'm trying to set a "NODE_ENV" environment variable during deployment via the ServiceDefentition.csdef file.
The variable is to be read in by my node.js app via process.env.NODE_ENV.
The documentation for this isn't very extensive (as it appears to be a very simple thing to do) but this is what I have been following: link1 link2
The section of the ServiceDefinition file I have is the following:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="userApiServer" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6">
<WebRole name="userApiWebRole" vmsize="Large">
...
<Runtime>
<Environment>
<Variable name="NODE_ENV" value="dev" />
</Environment>
</Runtime>
...
</WebRole>
</ServiceDefinition>
I've tried numerous variations; setting the env variable under a startup task instead on runtime, using xpaths to configuration settings but they just don't seem to be creating the env variables for me.
When messing around with the xpaths approach I did find that my configuration settings were being created on the instance, so the definition file is being read.
Are there any common (or uncommon) gotcha's or hidden details that I'm missing because for something apparently very simple I'm having a lot of trouble with it.

You can do it be editing either do it in web.config or iisnode.yml. Check out this answer
Set Node.js Environment Variable (NODE_ENV) in iisnode to Production/Development/Test

It is correct to set node_env variable in web.config and iisnode.yml as #AIDAN CASEY said.
Additionally, we can leverage pure Node.js 3rd part module dotenv. Just need to create a file named .env with the content:
node_env=production
include and initialize the module in Nodejs script:
require('dotenv').load();

Related

what are all the locations in which connectionStrings can be defined for an iis site?

I'm trying to find all the locations in which a connectionString can be defined for an iis site (to write a script to extract them all).
I know it can be part of a web.config. I would like to have a complete list of files it can be configured in.
Does it make sense for it to be configured in the site code?
Which other configuration files can define a site's connectionStrings?
And a bonus question - how do I know the order of the files in which the connectionString is searched in ?
Thanks,
EDIT:
Additional info - all IIS sites are pure dotnet sites.
Also, specifying the general location of files, rather then file names, is also helpful.
E.g. - connectionStings can be located in external configuration files, whose location is defined at a in an appSettings element in the "%runtime install path%\config\machine.config" file.
Another option is to just link to the relevant docs.
My issue is that I haven't found anything conclusive.
As far as I know, there are several ways to configure connectionstring in ASP.NET applications.
Define it in code. This is the method used by many beginners. Because at this time they focus on code learning and logical understanding. But some people are accustomed to using it if the database is fixed, it does not need to be modified.
SqlConnection connection = new SqlConnection("Data Source=.\\SQLEXPRESS;Initial Catalog=mytest;Integrated Security=True");
Define it in web.config or App.config. The benefit of it is easy to modified connectionstring after publishing application. Developers can change web.config, no need to change code and deploy application again.
<connectionStrings>
<add name="mytest" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=mytest;Integrated Security=True;" providerName="System.Data.SqlClient" />
</connectionStrings>
Using External Configuration Files. ConnectionString is stored in a independent file for example connections.config. The benefit of it is modifying an external configuration file does not cause an application restart.
<?xml version='1.0' encoding='utf-8'?>
<configuration>
<connectionStrings configSource="connections.config"/>
</configuration>
About list all connectionstrings, you can use ConnectionStringSettingsCollection. It can get a connection by name and provider name.
I found a pretty good source for the locations of the IIS dotnet Framework configuration files - https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc754617(v=ws.10)?redirectedfrom=MSDN#inheritance
You could define additional connectionStrings
In dotnet code.
In env.
In external config files.
For non-IIS scopes - such as user scopes and role scopes.
These 4 options are not specific to IIS.
I don't know where options (3) and (4) are defined, and I'm not sure if this list is complete. But by combing this list and the one in the doc, I think we have 99% coverage of defined connectionStrings.

How to get Azure Cloud startup environment variables to persist

For Azure Cloud Services, when you define Startup Tasks in your ServiceDefinition.csdef file, you have the option of setting environment variables. It looks something like this:
<Startup>
<Task commandLine="install.cmd" executionContext="elevated" taskType="simple">
<Environment>
<Variable name="YourEnvironmentVariable" value="YourValue"/>
</Environment>
</Task>
</Startup>
That environment variable only seems to persist for the duration of the Task it's defined in (in this case, running install.cmd). If you RDP into your cloud instance and check the environment variables, you won't see it listed there. Is there a way to get that environment variable to persist?
It doesn't appear as if the Azure Cloud Framework gives you an easy way to do this, but it's possible. I persisted the Environment Variable by having install.cmd manually set it. In my case, install.cmd called a PowerShell script that did the following:
# Make the environment variables defined in ServiceDefinition.csdef persist
[Environment]::SetEnvironmentVariable("YourEnvironmentVariable", "$Env:YourEnvironmentVariable", "Machine")
You could accomplish this without using PowerShell. It would look something like this:
setx YourEnvironmentVariable "%YourEnvironmentVariable%" /M

Refer a connectionstring from web config in another config file

I am using NLog to write logs to my database,
I have created a file NLog.config which is writing logs to a text file as of now.
To write the logs to a database, I am following this tutorial.
However, the connectionstrings for diferrent environments can be only modified in Web.config. (I am using Azure App services). Is there any way I can refer the connection string from web.config in NLog.config.
TIA
If you not using ASP.NET Core (but "full" ASP.NET), you could use ${appsetting:name=..}
Install NLog.Extended with Nuget and use ${appsetting:name=..} in your config file.
e.g.
<target name="database"
type="Database"
connectionString="${appsetting:name=myConnectionString}" />
See also the ${appsetting} documentation
NB: It can only read <appSettings> and not <connectionStrings>

How to override web.config values in custom section in Azure Web App?

It is possible in Azure Web App to override web.config AppSettings section easily. E.g. if I have the following web.config:
<appSettings>
<add key="AllowedCORSOrigin" value="http://localhost:26674"/>
</appSettings>
I can override it in the app settings UI in the portal like that:
I have also a custom section in the web.config:
<AdWordsApi>
<add key="OAuth2RefreshToken" value="TOKEN" />
</AdWordsApi>
Is it possible to override it somehow as well? I have tried AdWordsApi.OAuth2RefreshToken and AdWordsApi:OAuth2RefreshToken, but that does not work that easily.
P.S. It's interesting to know if it's possible with other custom sections like e.g if I want another authentication mode on the server.
<system.web>
<authentication mode="None" />
</system.web>
Short answer is that it is not possible.
The mechanism you describes only works with App Settings and Connection Strings. High level, the way it works is:
Your Azure App Settings become environment variables
At runtime, a special module sets those dynamically in the .NET config system. Note that the physical web.config is never modified.
But it would be hard to make such mechanism work on arbitrary config sections, as those could not be dynamically affected without modifying the physical file.
If you are using Visual Studio use web.config transformations to change configuration settings depending on whether you are running locally or deploying to Azure:
How to Transform Web.config
In simple terms you create one more more build configurations (typically Debug & Release). In your Visual Studio solution right-click on your existing web.config file and click "Add Config Transform", this will create a Web.Debug.Config and Web.Release.Config file which you can then customise with specific settings depending on the environment. Link this with your Azure build configuration and you can then have any combination of settings for local and remote deployment.
This is old but leaving this reference to how to use Azure Resource Manager to potentially solve this.
You can transform the values by the listed in VSTS by doing the following steps in App.Release.config:-
Add xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" in configuration section
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
</configuration>
Add xdt:Transform="Replace" in custom section like below
<AdWordsApi xdt:Transform="Replace">
<add key="OAuth2RefreshToken" value="TOKEN" />
</AdWordsApi>
Create variable token in the release pipeline e.g OAuth2RefreshToken
Then in file config use it as following
<AdWordsApi xdt:Transform="Replace">
<add key="OAuth2RefreshToken" value="#{OAuth2RefreshToken}#" />
</AdWordsApi>
If you are adding any in web.config --> Appsetting, you can overirde it in Azure App Service using variable prefix
Key Name: APPSETTING_AllowedCORSOrigin
Value: http://localhost:26674
https://learn.microsoft.com/en-us/azure/app-service/reference-app-settings?tabs=kudu%2Cdotnet#variable-prefixes

Azure connection string best practices

I have an application that I am just migrating to Azure. Currently I use web.config transformation to manage changing the database connecting string dev/staging/prod environments. How is it best to manage these multiple connection strings in Azure?
In cases where it doesn't matter if the developer can see production credentials, you can use the built-in Visual Studio 10 config transformations. If this is what you're looking for, follow these steps:
1.Navigate to your Azure project folder in file explorer
2. Make a copy of ServiceConfiguration.cscfg
3. Rename copy to ServiceConfiguration.Base.cscfg
4. For each build configuration (e.g. Dev, Staging, Production), create a ServiceConfiguration.<build config name>.cscfg file. In these files, you can use the normal config transformation syntax
5. Open your .ccproj file in a text editor
6. Find the following node,
<ItemGroup>
<ServiceDefinition Include="ServiceDefinition.csdef" />
<ServiceConfiguration Include="ServiceConfiguration.cscfg" />
</ItemGroup>
and replace it with this (you will have to edit this block to match your build configs):
<ItemGroup>
<ServiceDefinition Include="ServiceDefinition.csdef" />
<ServiceConfiguration Include="ServiceConfiguration.cscfg" />
<None Include="ServiceConfiguration.Base.cscfg">
<DependentUpon>ServiceConfiguration.cscfg</DependentUpon>
</None>
<None Include="ServiceConfiguration.Dev.cscfg">
<DependentUpon>ServiceConfiguration.cscfg</DependentUpon>
</None>
<None Include="ServiceConfiguration.Staging.cscfg">
<DependentUpon>ServiceConfiguration.cscfg</DependentUpon>
</None>
<None Include="ServiceConfiguration.Production.cscfg">
<DependentUpon>ServiceConfiguration.cscfg</DependentUpon>
</None>
</ItemGroup>
7.Add the following at the end of the .ccproj file, just above </Project>:
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets" />
<Target Name="BeforeBuild">
<TransformXml Source="ServiceConfiguration.Base.cscfg" Transform="ServiceConfiguration.$(Configuration).cscfg" Destination="ServiceConfiguration.cscfg" />
</Target>
8.If you're using a CI server that doesn't have Visual Studio 10 installed, you'll probably have to copy the C:\Program Files\MSBuild\Microsoft\VisualStudio\v10.0\Web folder and its contents from a development machine to the server.
Update: As #SolarSteve noted, you might have to add a namespace to your ServiceConfiguration.*.cscfg files. Here's an example of ServiceConfiguration.Base.cscfg:
<sc:ServiceConfiguration serviceName="MyServiceName" osFamily="1" osVersion="*" xmlns:sc="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<sc:Role name="MyRoleName">
<sc:Instances count="1" />
<sc:ConfigurationSettings>
<sc:Setting name="DataConnectionString" value="xxx" />
</sc:ConfigurationSettings>
</sc:Role>
</sc:ServiceConfiguration>
Personally we:
Dropped web config transformations completely.
Setting is retrieved from cscfg.
Development version of cscfg points to local development environment (that's stored in version control).
While deploying to production, we supply secure credentials for production SQL Azure and storage.
For sample of the settings management class that scans application settings and cloud environment for configuration values, you can check out open source Lokad.CQRS for Windows Azure project (see CloudSettingsProvider)
You can use CloudConfigurationManager in Azure SDK 1.7 http://msdn.microsoft.com/en-us/LIBRARY/microsoft.windowsazure.cloudconfigurationmanager
This starts by looking in the ServiceConfiguration.cscfg e.g. ServiceConfiguration.Cloud.cscfg for config setting. If it isn't there it falls back to web.config and app.config
For example
CloudConfigurationManager.GetSetting("StorageConnectionString")
Will look in the appropriate cscfgfile for StorageConnectionString setting, then it will search the web.config and then app.config.
We have a number of environments (local dev inside dev fabric, local dev outside dev fabric, testing, release which has 2 versions: release/prod and release/staging and 20 projects some of which need some variability in configure settings. We solved this problem by creating a tiny "config" project, included subfolders there that match the environments. We copy files from the subfolder depending on which build we're doing into root folder of the config project, during every compile.
All other projects link to the config project for .config files. We also use partial config files to keep the insanity of repeating the same info all the time across various environments.
Hope this helps
I had the same requirement for transforming ServiceConfiguration.
I went with the answer from jmac (thank you!), but had trouble with the namespace in the Base version:
<ServiceConfiguration serviceName="TestCloud2" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="1" osVersion="*">
after a bit more poking around found this by Andrew Patterson (Thank You).
so my resulting transform file:
<asc:ServiceConfiguration serviceName="TestCloud2" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xmlns:asc="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="1" osVersion="*">
<asc:Role name="WebRole1">
<asc:Instances count="1" />
<asc:ConfigurationSettings>
<asc:Setting name="LoggingStorage" value="UseDevelopmentStorage=true" xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</asc:ConfigurationSettings>
</asc:Role>

Resources