Azure App Service Application Settings Ignored, Using web.config Instead - azure

I recently deployed an ASP.Net Web API project to our Azure App Service test slot but started receiving an error when making requests to the API endpoints. Through remote debugging, it became clear that the app was extracting my dev connection strings from the deployed web.config file.
The connection strings are supposed to come from the Application Settings we set up via the Azure Portal - and, in previous deployments, they were - but that's not the case.
Why would this happen and what can be done to ensure the correct behaviour occurs? We absolutely don't want our production database secrets being put into GIT via the web.config...

I recently experienced the same problem and fixed it:
In Azure App Services, the machine-wide web.config file is located at D:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config.
This file differs to a normal machine-wide web.config file because it has this extra element:
<system.web>
...
<compilation>
<assemblies>
<add assembly="EnvSettings, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
...
</assemblies>
</compilation>
</system.web>
The EnvSettings.dll assembly is located inside D:\Program Files\IIS\Microsoft Web Hosting Framework (unfortunately this directory is access-controlled and I can't get into it).
But EnvSettings.dll is mirrored in the GAC, so I was able to copy it from there.
Inside EnvSettings.dll is an [assembly: PreApplicationStartMethod] attribute that runs a method in EnvSettings.dll which copiesthe APPSETTING_ and database connection-string settings from Environment Variables into the .NET Framework ConfigurationManager.AppSettings and ConfigurationManager.ConnectionStrings collections.
Note this copying only happens once (during application startup), and only in the first AppDomain - so if you have other AppDomain instances in your application they won't see the updated ConfigurationManager.
Therefore, if you see that your Azure Portal configuration settings for your App Service are not being used when you dump your ConfigurationManager, then the following is likely happening:
You used <clear /> in your <compilation><assemblies> element, which stops EnvSettings.dll from being loaded at all.
In which case you need to either add back the <add assembly="EnvSettings... element from above to your own web.config, or find some other way to load it.
I don't recommend saving EnvSettings.dll locally and adding an assembly reference to your project, as EnvSettings.dll is part of the Microsoft Web Hosting Framework.
Or you have code that is clearing or resetting ConfigurationManager after EnvSettings populates it for you.
Or something else is going on that I have no idea about!
As an alternative to having EnvSettings.dll copy your settings over, another option is to copy the environment-variables over yourself - and as you control the code that does this it means you can call it whenever you need to (e.g. if you ever reset them).
Here's the code I used:
public static class AzureAppSettingsConfigurationLoader
{
public static void Apply()
{
foreach( DictionaryEntry environmentVariable in Environment.GetEnvironmentVariables() )
{
String name = (String)environmentVariable.Key;
String value = (String)environmentVariable.Value;
if( name.StartsWith( "APPSETTING_", StringComparison.OrdinalIgnoreCase ) )
{
String appSettingName = name.Substring( "APPSETTING_".Length );
ConfigurationManager.AppSettings[ appSettingName ] = value;
}
else if( name.StartsWith( "SQLAZURECONNSTR_", StringComparison.OrdinalIgnoreCase ) )
{
String csName = name.Substring( "SQLAZURECONNSTR_".Length );
ConfigurationManager.ConnectionStrings.Add( new ConnectionStringSettings( csName, value, providerName: ""System.Data.SqlClient" ) );
}
}
}
}

See my sample here: http://mvc5appsettings.azurewebsites.net/
// My web.config also has a "HERO_TEXT" key in
// that reads "Value from web.config"
string hero = ConfigurationManager.AppSettings["HERO_TEXT"];
Wiki page on App Settings for .NET:
https://github.com/projectkudu/kudu/wiki/Managing-settings-and-secrets
As already mentioned here, make sure you have that App Setting in the right slot.

As I know, the settings in Azure portal will override existing setting in Web.config. So If you want to ignore the Azure Application settings in portal and use Web.config instead. I am afraid you need to configure the settings in web.config, and remove the same key/pair in Azure portal.

Related

Configure Azure Web Sites/Jobs app settings when developing locally

As described in this article: https://azure.microsoft.com/en-us/blog/windows-azure-web-sites-how-application-strings-and-connection-strings-work/, Azure Web Apps/Web Sites/Web Jobs can take their configuration settings (appSettings, connectionString) from environment variables instead of app.config/web.config.
For example, if an environment variable named "APPSETTING_appSettingKey" exists, it will override the following setting from app.config/web.config:
<appSettings>
<add key="appSettingKey" value="defaultValue" />
</appSettings>
This works fine once the application is deployed in Azure, but I would like to use the same method when testing locally.
I tried to emulate this in a local command line:
> set APPSETTING_appSettingKey=overridedValue
> MyWebJob.exe
The web job accesses this setting using:
ConfigurationManager.AppSettings["appSettingKey"]
When running in Azure, it reads the value "overridedValue" as expected, but locally it reads the value "defaultValue" from the app.config file.
Should I expect this to work, or is this implemented only under an Azure environment?
I could obviously create an abstraction over ConfigurationManager that emulates this, but this wouldn't work when calling code that needs a connection string name instead of a connection string value. Also, I want to use the same method regardless of the environment to simplify management of settings.
There are 3 reasons why I need this:
1) I don't like the idea of deploying to production a web.config file that references connection strings, etc for a developement environment, because there's a risk of an error that would cause the development settings (in web.config) to be used in production (production web app connecting to development database, etc), for example if an environment variable is named incorrectly (after renaming the setting in web.config but forgetting to rename it in environment variables)
2) I'm trying to setup development environments where each developer has his own isolated cloud resources (storage account, databases,...). Currently, everyone has to manually edit his .config files to reference the correct resources, and be careful when checking-in or merging changes to these files.
3) A solution can have multiple projects that need to duplicate the same settings (main web app, web jobs, integration test projects,...). This causes a lot of work to ensure updated settings are replicated across all files.
This would be simplified if there was an environment-independent .config file without any actual configuration, each developer would configure a set of environment variables once and be able to use them for all parts of a solution.
Yes, this special transformation of environment variables into config values is done via a component that is specific to Azure WebApps and won't be in play locally.
Generally people are fine with the local behavior this produces - locally you are reading from config settings as usual, but in Azure you're reading from secure settings that were configured via the App Settings portal blade (so these settings aren't in your source code).
You could write an abstraction over this if you wish, E.g. the WebJobs SDK actually does this internally (code here).
When I am developing locally and want to consistantly use Environment.GetEnvironmentVariable. In my static class Main I have the following code:
if (config.IsDevelopment)
{
config.UseDevelopmentSettings();
Environment.SetEnvironmentVariable("UseDevelopmentSettings", "true");
}
Then in my static class Functions I add a static constructor and in there I call the static method below:
static void AddAppSettingsToEnvironmentVariables()
{
String useDevelopmentSettings = Environment.GetEnvironmentVariable("UseDevelopmentSettings"); ;
if (!(String.IsNullOrEmpty(useDevelopmentSettings)))
{
foreach (String key in ConfigurationManager.AppSettings.AllKeys)
{
Environment.SetEnvironmentVariable(key, ConfigurationManager.AppSettings[key]);
}
}
}
The code is small enough that I can simply comment it out before I test in Azure.
If you want to test the application with the value that will be used in Azure portal AppSettings/Connection String. I would recommend use HostingEnvironment.IsDevelopmentEnvironment. To ensure it will work, please change the <compilation debug="true" targetFramework="4.5.2" /> to <compilation debug="false" targetFramework="4.5.2" />. set the value with the same value in Azure portal if (HostingEnvironment.IsDevelopmentEnvironment == false). I have try with a simple project, hope it helps:
public ActionResult Index()
{
if (HostingEnvironment.IsDevelopmentEnvironment == true)
{
ViewBag.Message = "Is development.";
}
else
{
ViewBag.Message = "Azure environment.";
}
return View();
}
Here is the result:

Azure webjobs not reading the site appsettings

I've got an azure webjob, that has some appsettings for api keys etc.
I've also got a bunch of PRODUCTION azure app settings (specified in the portal), that should override my webjob config appsettings.. But they don't.
For my website, they work as expected, and all is fine. For the webjobs however, they just get completely ignored, and my app settings from the config are used instead.
Is this a bug in azure? All the docs suggest that this should work.
EDIT
I found this blog all about using CloudConfigurationManager.GetSetting so I've implemented that and it still won't work - still using the settings that are defined in web job's app settings file :(
Thanks
So it looks like I've found a bug!
It's because my AppSettings were referenced from another file, like this (in app.config):
<AppSettings file="appsettings.config"/>
This basically breaks azure's config management.
Use
"D:\home\site\wwwroot\" to create an absolute path to files inside your website.
inside your WebJob to point to any file inside your wwwwroot directory. Using the Absolute path with D:\home\site\wwwroot\appsettings.config should fix you website.
Did you set your settings only in the Web.config file or did you set them in the portal or using the VS "Website Settings" tooling? You need to set the WebJobs-related settings at that level, not just in the Web.config. Once you do that, restart your site, and the settings should be there.
I had a similar problem but for me it was that we set the "is_in_place" settings.job value to true. I guess when it's in place, it doesn't update the config file with the settings. We didn't have a strict requirement that it run in place, so removing that setting fixed the problem for us.
I have a similar problem with several web jobs sharing a common settings file. It would be inconvenient to duplicate the settings in each job.
Someone mentioned using configSource= instead of file= in the app.config to reference the external config settings file. I tried this, and it appears that it now works as expected. The settings are being taken from the Portal App Settings instead of the file now.
Fortunately, the settings for the web jobs all come from the external file. The use of file= allowed me to use additional per-app settings other than just those in the file, but fortunately I don't need to do that.
A workaround to this problem is to place the settings inline in the AppSettings tag of the Web.config like this.
<AppSettings>
<add key="host" value="someHost" />
</AppSettings>
Azure App Service Application Settings are persisted in the Environment Variables. Go to the Azure Portal add your application settings or connection string values. Then, you can check out the environment variables of your app service at https://sitename.scm.azurewebsites.net
If you want your webjobs to share those settings, in your webjob project, create a appsettings.json:
{
"APPSETTING_AzureWebJobsDashboard": "",
"APPSETTING_AzureWebJobsStorage": "",
"SQLAZURECONNSTR_xxx": ""
}
In your Main() method
private static void Main(string[] args)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
var configurations = builder.Build();
var services = new ServiceCollection()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(configurations["SQLAZURECONNSTR_xxx"]),
ServiceLifetime.Transient)
.BuildServiceProvider();
var host = new JobHost(new JobHostConfiguration
{
DashboardConnectionString = configurations["APPSETTING_AzureWebJobsDashboard"],
StorageConnectionString = configurations["APPSETTING_AzureWebJobsStorage"]
});
host.RunAndBlock();
}
This is simpler than trying to figure out the path to the website config on the app service

Disabling request validation on Azure Websites

My node.js application runs nicely on my own machine, however, after pushing it up to an Azure WebSite using Git, I'm getting request validation problems.
Some of my requests are trapped by the IIS validation process. The fix is to add this to the web.config:
<httpRuntime requestPathInvalidCharacters=""/>
I downloaded the web.config from the site\wwwroot folder of my website using FTP, added it to the repo, added the new element in the XML, and pushed it back up to Azure.
My web.config file seems to have been overridden by the default.
Is there a way of changing this behaviour? Or another way of turning off request validation? Or am I just being thick?
UPDATE
I take it all back, it seems to be express which is blocking the request. However, the question still stands as 'how do I customise my web.config?'
Could you try setting a custom validation type? Like this:
<httpRuntime requestPathInvalidCharacters=""
requestValidationType="MyValidator, MyAssembly"/>
And the class:
public class MyValidator : RequestValidator
{
protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
{
validationFailureIndex = 0;
return true;
}
}

Combined Azure web role and worker role project not seeing app.config when deployed

I'm implementing the combined web/worker role scenario as described here where you simply add the following to your worker role:
public override void Run()
{
// This is a sample worker implementation. Replace with your logic.
Trace.WriteLine("WorkerRole1 entry point called", "Information");
while (true)
{
Thread.Sleep(10000);
Trace.WriteLine("Working", "Information");
}
}
The problem, as noted in the post's comments, is that this worker process cant read web.config so you have to add an app.config. It is also noted that app.config does not get deployed automatically.
So my question is how do I configure my project so app.config will get deployed?
I've added app.config to my project, set the Build Action to "Content", and "Copy always"
THIS WORKS FINE IN THE EMULATOR, but not when deployed to Azure.
Note: I noticed in the emulator a projectname.dll.config is created, but not when deployed to Azure.
I'm using VS2010, Windows Azure Tools 2011
I know some will suggest using the .cscfg file instead, but many of my components get their settings from web.config/app.config:
Elmah, Transient Fault Handling Client, Diagnostics, Email, etc...
Please read thoroughly this blog post. It explains in great details what is happening in Windows Azure Web Role with Full IIS.
What you need to do, is to add a WaIISHost.exe.config file (with copy to output = copy always). And put all the configurations you need in that file. This is because, your code (RoleEntryPoint) lives in WaIISHost.exe process, and not your pdojectName.dll process.
For me using Azure SDK 1.8 and deploying my Web Worker Role from the Visual Studio using publish, I had to include a config file, named. ProjectName.Dll.config with my settings. The configuration from app.config is not picked up by the web role when running in windows azure. And the app.config file is not converted into a ProjectName.Dll.config and added automatically to the bin folder of the deployment package, so you have to create it by hand and set it to copy always.
I'm using Azure SDK 2.0 and OS Family 3, and has been very confused about this. So I created a MVC 4.0 website with all 4 config files suggested in various answers. That is:
Web.config
App.config
WaIISHost.exe.config
[AssemblyName].dll.config
All but Web.config was set to "Copy if newer".
In the configs file I wrote:
<appSettings>
<add key="AppSettingFile" value="[NameOfConfigFile]"/>
</appSettings>
In the WebRole.cs I have the following code:
public class WebRole : RoleEntryPoint
{
public override void Run()
{
string appSetting = ConfigurationManager.AppSettings["AppSettingFile"] ?? "No config file found";
Trace.TraceInformation("Config file: " + appSetting);
while (true)
{
...
}
}
}
Result when deployed with 4 .config files:
"Config file: App.config". So App.config must be the answer, right?
Wrong! Result when deployed with only Web.config and App.config:
"Config file: No config file found". Hmm wierd.
Result when deployed with Web.config, App.config and [AssemblyName].dll.config:
"Config file: [AssemblyName].dll.config". So [AssemblyName].dll.config must be the answer, right?
Wrong! Result when deployed with only Web.config and [AssemblyName].dll.config:
"Config file: No config file found". WTF!
Result when deployed with only Web.config and WaIISHost.exe.config:
"Config file: No config file found".
Result when deployed with Web.config, App.config and WaIISHost.exe.config:
"Config file: No config file found". WTF!
So my conclusion is that you need to have 3 or 4 config files to be able to configure the Worker role of a Web project.
This is clearly a bug. Personally I think the intention from MS was to change from WaIISHost.exe.config to App.config (to align with Worker Roles and .NET in general). But App.config is only used when all 4 .config files exists.
So for now I'm having Web.config and both App.config and [AssemblyName].dll.config, and they contain exactly the same.
Hopefully going forward with Azure SDK 2.x we can use only App.config and Web.config.

Sharepoint 2010 - web.config modification

We have a farm with 2 servers.
I have applied some changes to the web.config on both servers. (I have a specific web application i.e. I have applied the changes in the web.config of my sharepoint web application and NOT the default Sharepoint site or the central admin site)
But it seems that Sharepoint does not take into consideration these changes!
For example I added an assembly reference .... but sharepoint was still throwing an assembly reference exception. i had to add the assembly reference to each and every control.
I have also increased the execution timeout but it still gives timeouts.
This happens in the production environment only.
In the test (where there is a single server) I update the web.config and all changes work.
Is it because I should not be updating the web config. I have noticed there is an SPWebConfigModification class. Do I have to use this ? won't it do the same changes as I would have done manually.
Update ....
I have now used the SPWebConfigModification and also did an iisreset ... but the changes were simply ignored!
Update 2...
Some more details on my web.config updates
I had added an assembly reference under assemmblies sectuion, somethign like this:
This did not work as Sharepoint was still throwing an exception that the assembly cannot be found.
This problem only happens in the production environment. In dev and test, I was also receiving the exception but when I added the assembly reference above, the error disappeared.
Another thing which did not work is the executionTimeout. I have added this to the production environment but sharepoint is still giving timeouts an a long request wich we have. Again, this entry solved the problem in the test and development environments.
I wrote this for this for Sharepoint 2007, I think you need to modify the impersonation (RunWithElevatedPrivileges) but the rest should work:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPSecurity.RunWithElevatedPrivileges(delegate() {
try
{
Trace.WriteLine("Try to modify web.config");
SPWebApplication myWebApp = ((SPWeb)properties.Feature.Parent).Site.WebApplication;
WebConfigModifier mod = new WebConfigModifier(myWebApp, OwnerString);
mod.AddModification(
"SafeControl[#Assembly='Elsni.WorldsBestProgram, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e7639c2c71f2f003']",
"configuration/SharePoint/SafeControls",
"<SafeControl Assembly='Elsni.WorldsBestProgram, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e7639c2c71f2f003' Namespace='GFA.UniversalListSyncSolution' TypeName='*' Safe='True' />"
);
mod.AddModification(
"add[#key='PropertiesSiteUrl']",
"configuration/appSettings",
"<add key=\"PropertiesSiteUrl\" value=\"http://iei-developersy/sites/gfaadmin/\" />"
);
mod.Update();
Trace.WriteLine("Done.");
}
catch (Exception ex)
{
Trace.WriteLine("ERROR while activating feature: " + ex.Message);
}
}
});
}
As you have pointed out, you need to make these changes using the SPWebConfigModification class. It is possible to make the changes manually, however, this usually results in random issues caused by replication issues etc ....
The SPWebConfigModification class will ensure the change is stored in the SP database and amend the web.config files on your behalf.

Resources