I've got an azure app service that I've set up like this:
But when I call IConfiguration.GetConnectionString("db") I get null back.
I've read articles like this https://mderriey.com/2018/08/21/azure-app-service-connection-strings-and-asp-net-core/ which say "it just works", but they're all several years old. I assume something's changed, but what?
Enumerating over all settings in my IConfiguration object I've got no connection strings. I do in development, where my appsettings.development.json has a connectionStrings: { db: "" } defined.
I can see and read the ENV variable: POSTGRESQLCONNSTR_db from within code, and it's value is correct (what I've set via the Azure portal).
Should I expect to be able to do IConfiguration.GetConnectionString("db")? Or am I expected to switch between reading env variables in prod vs dev.
Do I need to include some nuget package to make IConfiguration work under Azure with these ENV variables and their mad prefixes?
My startup.cs basically looks like:
public Startup(IConfiguration configuration)
{
this.Configuration = configuration;
}
public IConfiguration Configuration { get; }
Nothing else in there of interest to this question.
The POSTGRESQLCONNSTR_ prefix isn't supported by the environment variables configuration provider. The docs shows this, in an indirect fashion, where it states that the following prefixes are supported:
CUSTOMCONNSTR_
MYSQLCONNSTR_
SQLAZURECONNSTR_
SQLCONNSTR_
It's also apparent in the source code for the provider.
There are a couple of options for working around this:
Change the Type to Custom in the Connection strings section of the Azure portal.
Change to an Application setting of ConectionStrings:db in the Azure portal.
This is being tracked on GitHub: https://github.com/dotnet/runtime/issues/36123.
I got confused as well, so here it is:
You have two options to specify Connection String locally:
launchSettings.json (environmentVariables section)
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"SQLAZURECONNSTR_SomeConnectionString": "DefaultEndpointsProtocol=blah"
}
appSettings.json
"ConnectionStrings": {
"SomeConnectionString": "DefaultEndpointsProtocol=blah"
}
Having either way will allow you to get the connection string setting by calling:
IConfiguration.GetConnectionString("SomeConnectionString")
Function call above will also work when deployed to Azure, as it is using EnvironmentVariables configuration provider to read settings.
Instead of getting the config from the interface
IConfiguration.GetConnectionString("db")
try to get it from
Configuration.GetConnectionString("db")
And in production you have an empty string in production.appsetting.json and add the value in azure(appservice) configuration directly under connectionstrings(this will override the json setting file). And no nugets are needed for reading from appsettings
Related
EDIT: This question has been significantly restructured, now I've figured out a bit more of the problem and this should clarify things.
I am following this tutorial: https://learn.microsoft.com/en-us/azure/app-service/tutorial-dotnetcore-sqldb-app
I've deployed my own multiproject app, which works, but I can't get the connection string working properly. For some reason, it only works if I hardcode the connection string into the OnConfiguring method of my DBContext class. Otherwise, it throws an error.
Like so:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(
"Nasty hard coded azure connection string",
providerOptions => { providerOptions.EnableRetryOnFailure(); });
}
However, obviously, i want to get the connection string from a configuration file or environment variable.
Prior to deploying, I had the following. An extension method for IServiceColleciton which sets up the connection string:
public static void ConfigureSqlContext(this IServiceCollection services,
IConfiguration configuration) =>
services.AddDbContext<PeakedDbContext>(opts =>
opts.UseSqlServer(configuration.GetConnectionString("defaultConnection")));
then this method is called in program.cs. A pretty normal setup.
And I also set up an IDesignTimeDBContextFactory like so:
public class RepositoryContextFactory : IDesignTimeDbContextFactory<PeakedDbContext>
{
public PeakedDbContext CreateDbContext(string[] args)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var builder = new DbContextOptionsBuilder<PeakedDbContext>()
.UseSqlServer(configuration.GetConnectionString("defaultConnection"));
return new PeakedDbContext(builder.Options);
}
}
Both my appsettings.json AND the Azure App Service configuration have the same name "defaultConnection".
As far as I can tell this is the approach recommended here: https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli
I have also tried adding an empty constructor for my DBContext. (Not sure how this affects things as I have other DIs on my DBContext constructor. My DBContext consructors are getting a bit out of hand:
public PeakedDbContext()
{
}
public PeakedDbContext(DbContextOptions options) : base(options)
{
}
public PeakedDbContext(DbContextOptions options, ICurrentUserService currentUserService) : base(options)
{
_currentUserService = currentUserService;
}
According the the second link, above, I shouldn't need OnConfiguring method in my DBContext... and even if I do, what is the correct way to pass access to configuration.GetConnectionString, instead of hardcoding the connection string? Should I just add yet another DBContext constructor with the config injected? However, it ONLY works if I have the onconfiguring method. Neither the contextfactory nor the extension method setup are being used by azure app service.
Shouldn't it use the designtime factory or the hostconfiguration extension method I've set up above? What is the right way to use _configuration.GetConnectionString("defaultConnection") so that it works both locally and on Azure Deployment?
Update:
Still no luck. I tried adding the database connection string as an environment variable on azure like so:
and then updating all my reference to getconnection string - in program.cs, IDesignFactory and OnConfiguring - like so:
Environment.GetEnvironmentVariable("PeakedDbConn")
This continues to work locally. But When deploying to Azure it claims the connection string in null... so it's not seeing this variable. Nor can I find any code that will access the defaultConnection from the image. Which is strange, because it accesses the SECRET variable just fine.
I have followed the same code which you have provided with few changes.
Check the below steps to get the Connection string from appsettings.json and override the value if Azure App Connection String has been set.
As you are using .NET Core 6, I have set all the Configurations in Program.cs itself.
My Program.cs
builder.Services.AddDbContext<MyDatabaseContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("MyDbConnection")));
builder.Configuration.AddEnvironmentVariables();
Same Connection String name must exist in both Local and Azure App Connection Strings.
My appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"MyDbConnection": "Dummy Connection String"
}
}
Azure App Connection String:
To check if we are getting the Connection String Value, I have written code in Controller.
private readonly IConfiguration Configuration;
public HomeController(ILogger<HomeController> logger,IConfiguration config)
{
_logger = logger;
Configuration = config;
}
public IActionResult Index()
{
var myconnStr = Configuration.GetConnectionString("MyDbConnection");
ViewBag.myconnStr = myconnStr;
return View();
}
My .csproj file :
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureAppConfiguration" Version="5.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
</ItemGroup>
</Project>
Local Output:
Deployed App Output:
Ok so it turned out to be GitHub actions that was the problem. The tutorial I followed in the first link doesn't mention this, perhaps because it's a single project api... not exactly sure.
The tutorial uses github actions to build and deploy the app, but for me, during the build it fails saying there is no connection string. This is because GitHub build process doesn't have access to either your local or the azure environment variable.
So I had to go into setting on my github repo and on the left click on secrets and variables < actions.
Click create a new Repository Secret, give it the same name as your environment variable i.e. PEAKEDDBCONN for me. Then, give it a value. I just used my local host string, but I guess you could type 'monkeynuts' in here if you wanted, it just needs to not be null.
Then you need to add a line to your workflow yaml file, the same one the tutorial talks about, to tell it about the environment variable. I added it like so:
jobs:
build:
runs-on: ubuntu-latest
env:
PEAKEDDBCONN: ${{ secrets.PEAKEDDBCONN }}
Then it all builds nicely and works.
For anybody who it helps, I decided to blog this whole setup:
https://garyfrewin.hashnode.dev/setting-up-an-entity-framework-core-web-api-on-azure-with-sqlserver-a-step-by-step-guide-for-hobby-projects
I've been working with functions with Azure, I've built a very simple Http Function locally by following the example linked here, the only difference is I've defined a User table instead of a Todo table
Everything works as expected locally, I'm able to post and get.
However, when deploying the function and trying to make a POST request I see the following within the logs:
Executed 'User' (Failed, Id=5df9dffe-eedf-4b11-aa10-54fda00992b0, Duration=1ms)System.ArgumentNullException : Value cannot be null. (Parameter 'connectionString')
I've checked the SQL Server to ensure it's accessible by other Azure Services just encase that was causing a problem, but I can confirm it's set to allow.
I have found this question, I've gone through the steps and checked against mine and I can confirm my Function App configuration does have the AzureWebJobsStorage connection string.
I'm not 100% sure why this would be happening due to my lack of knowledge of functions at the moment, have anyone else experience this? if so how did you resolve it?
Update
After further testing, it seems the error is coming from my Startup class,
class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
string connectionString = Environment.GetEnvironmentVariable("SqlConnectionString");
builder.Services.AddDbContext<ApplicationDbContext>(
options => SqlServerDbContextOptionsExtensions.UseSqlServer(options, connectionString));
}
}
Upon deployment, connectionString variable is null.... not sure why though.
Yes, you can not get it because you didn't set it in the configuration settings.
If you want to use the Connection Strings section.
Add the "ConnectionStrings":{} section to your local.settings.json file then add your connection string
{
...
"ConnectionStrings": {
"MyConnectionString": ""
}
}
Then you need to set the connection string in the Settings section of the Function App in the Azure Portal.
The scroll down to the Connection Section
And add a new connection string. Make sure it has the same name as you connection in the local.settings.json file.
Your question isn't 100% clear if this is happening locally (as you refer to local.settings.json) or when deploying. If this occurs when deploying, changing your local.settings.json file will not help, unfortunately.
You will need to add the Application Setting within the Azure Portal (located under Settings -> Configuration -> Application Settings -> New application setting).
You will need to save the application setting, and then restart the Azure Function instance for the changes to reflect.
Check out https://learn.microsoft.com/en-us/azure/azure-functions/functions-how-to-use-azure-function-app-settings?tabs=portal
I have an Azure function, and I'm using the DI system in order to register some types; for example:
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services
.AddTransient<IMyInterface, MyClass>()
. . . etc
However, I also was to register some data from my environment settings. Inside the function itself, I can get the ExecutionContext, and so I can do this:
IConfiguration config = new ConfigurationBuilder()
.SetBasePath(context.FunctionAppDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
However, in the FunctionsStartup, I don't have access to the ExecutionContext. Is there a way that I can either get the ExecutionContext from the FunctionsStartup class or, alternatively, another way to determine the current running directory, so that I can set the base path?
While the checked answer to this question is correct, I thought it lacked some depth as to why. The first thing you should know is that under the covers an Azure Function uses the same ConfigurationBuilder as found in an ASP.NET Core application but with a different set of providers. Unlike ASP.NET Core which is extremely well documented (https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/) this is not the case for Azure Functions.
To understand this set of providers you can place the following line of code in the Configure(IFunctionsHostBuilder builder) method of your FunctionStartup class,
var configuration = builder.Services.BuildServiceProvider().GetService<IConfiguration>();
place a debug break point after the command, execute your function in debug mode and do a Quick Watch… on the configuration variable (right click the variable name to select Quick Watch…).
The result of this dive into the code execution is the following list of providers.
Microsoft.Extensions.Configuration.ChainedConfigurationProvider
MemoryConfigurationProvider
HostJsonFileConfigurationProvider
JsonConfigurationProvider for 'appsettings.json' (Optional)
EnvironmentVariablesConfigurationProvider
MemoryConfigurationProvider
The ChainedConfigurationProvider adds an existing IConfiguration as a source. In the default configuration case, adds the host configuration and setting it as the first source for the app configuration.
The first MemoryConfigurationProvider adds the key/value {[AzureWebJobsConfigurationSection, AzureFunctionsJobHost]}. At least it does this in the Development environment. At the time I am writing this I can find no documentation on the purpose of this MemoryConfigurationProvider or AzureWebJobsConfigurationSection.
The HostJsonFileConfigurationProvider is another one of those under the covers undocumented providers, however in looking at documentation on host.json (https://learn.microsoft.com/en-us/azure/azure-functions/functions-host-json) it appears to be responsible for pulling this metadata.
The JsonConfigurationProvider for appsettings.json appears to be an obvious correlation to ASP.NET Core’s use of appsettings.json except for one thing which is it does not work. After some investigation I found that the Source FileProvider Root was not set to the applications root folder where the file is located but instead some obscure AppData folder (C:\Users%USERNANE%\AppData\Local\AzureFunctionsTools\Releases\3.15.0\cli_x64). Go fish.
The EnvironmentVariablesConfigurationProvider loads the environment variable key-value pairs.
The second MemoryConfigurationProvider adds the key/value {[AzureFunctionsJobHost:logging:console:isEnabled, false]}. At least it does this in the Development environment. Again, at the time I am writing this I can find no documentation on the purpose of this MemoryConfigurationProvider or AzureFunctionsJobHost.
Now the interesting thing that needs to be pointed out is that no where in the configuration is any mention of local.settings.json. That’s because local.settings.json is NOT part of the ConfigurationBuilder process. Instead local.settings.json is part of Azure Functions Core Tools which lets you develop and test your functions on your local computer (https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local). The Azure Function Core Tools only focus on specific sections and key/values like IsEncrypted, the Values and ConnectionString sections, etc. as defined in the documentation (https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local#local-settings-file). What happens to these key/values is also unique. For example, key/values in the Values section are inserted into the environment as variables. Most developers don’t even notice that local.settings.json is by default set to be ignored by Git which also makes it problematic should you remove the repository from you development environment only to restore it in the future. Something that ASP.NET Core has fixed with app secrets (https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets).
So, what happens if we create our own configuration with ConfigurationBuilder as suggested in the original question
IConfiguration config = new ConfigurationBuilder()
.SetBasePath(context.FunctionAppDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
or using the example shown in one of the other answers?
ExecutionContextOptions executionContextOptions = builder.Services.BuildServiceProvider().GetService<IOptions<ExecutionContextOptions>>().Value;
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.SetBasePath(executionContextOptions.AppDirectory)
.AddEnvironmentVariables()
.AddJsonFile("appsettings.json", false)
.AddJsonFile("local.settings.json", true)
.AddUserSecrets(Assembly.GetExecutingAssembly(), true);
The following are just a few of the issues with both examples.
The second example is incorrectly ordered as AddEnvironmentVariables should come last.
Neither of the examples mentions the need for the following line of code.
List item
builder.Services.AddSingleton<IConfiguration>(configurationBuilder.Build());
Without this line the configuration only exist in the Configure(IFunctionsHostBuilder builder) method of your FunctionStartup class. However, with the line you replace the configuration your Azure Function build under the covers. This is not necessarily a good thing as you have no way of replacing providers like HostJsonFileConfigurationProvider.
Reading the local.settings.json file (.AddJsonFile("appsettings.json")) will NOT place the key/value pairs in the Values section into the configuration as individual key/value pairs as expected, but instead group them under the Values section. In other word, if for example you want to access {["AzureWebJobsStorage": ""]} in Values you might use the command configuration.GetValue("Values:AzureWebJobsStorage"). The problem is that Azure is expecting to access it by the key name "AzureWebJobsStorage". Even more interesting is the fact that since local.settings.json was never part of the ConfigurationBuilder process this is redundant as Azure Functions Core Tools has already placed these values into the environment. The only thing this will do is allow you to access sections and key/values not defined as part of local.settings.json (https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local#local-settings-file). But why would you want to pull configuration values out of a file that will not be copied into your production code?
All of this brings us to a better way to affect changes to the configuration without destroying the default configuration build by Azure Function which is to override the ConfigureAppConfiguration method in your FunctionStartup class (https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#customizing-configuration-sources).
The following example takes the one provided in the documentation a step further by adding user secrets.
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
FunctionsHostBuilderContext context = builder.GetContext();
builder.ConfigurationBuilder
.SetBasePath(context.ApplicationRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
.AddJsonFile($"appsettings.{context.EnvironmentName}.json", optional: true, reloadOnChange: false)
.AddUserSecrets(Assembly.GetExecutingAssembly(), true, true)
.AddEnvironmentVariables();
}
By default, configuration files such as appsettings.json are not automatically copied to the Azure Function output folder. Be sure to review the documentation (https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#customizing-configuration-sources) for modifications to your .csproj file. Also note that due to the way the method appends the existing providers it is necessary to always end with .AddEnvironmentVariables().
You don't need any Configuration object in Azure Functions (v2). All the app settings get injected as Environment variables. So you can do just a simple Environment.GetEnvironmentVariable()
When running locally the local.settings.json gets read in the same way.
see here: https://learn.microsoft.com/en-us/sandbox/functions-recipes/environment-variables?tabs=csharp
There's a solid way to do this, answered here:
Get root directory of Azure Function App v2
The fact that Function Apps use environment variables as the typical way to get configuration is, while true, not optimal IMO. The ability to acquire an appsettings.json file in addition to items that deserve to be environment variables has its place.
The number of env vars being set via the DevOps task: "Azure App Service Deploy" option "Application and Configuration Settings" > "App settings" gets completely out of hand.
This is my implementation of it at the time of this writing:
ExecutionContextOptions executionContextOptions = builder.Services.BuildServiceProvider().GetService<IOptions<ExecutionContextOptions>>().Value;
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.SetBasePath(executionContextOptions.AppDirectory)
.AddEnvironmentVariables()
.AddJsonFile("appsettings.json", false)
.AddJsonFile("local.settings.json", true)
.AddUserSecrets(Assembly.GetExecutingAssembly(), true);
This allows me to leverage my release process variables to do environment specific "JSON variable substitution" for the bulk of my configuration, which lives in a nicely structured appsettings.json that is set to Copy Always. Notice that the loading of appsettings.json is set to not optional (the false setting), while I have local settings and secrets set to optional to accommodate local development.
appsettings.json can then be formatted nice and structured like this. Release variables named properly, e.g. "MyConfig.Setting" will replace the value properly if you set your release to do JSON variable substitution.
{
"Environment": "dev",
"APPINSIGHTS_INSTRUMENTATIONKEY": "<guid>",
"MyConfig": {
"Setting": "foo-bar-baz"
}
}
While local.settings.json remains in the flat style:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=<accountname>;AccountKey=<accountkey>;EndpointSuffix=core.windows.net",
"Strickland:Propane:Config": "Dammit, Bobby!"
}
}
In addition, I set some App settings (env vars) to Azure KeyVault References in the release process, as well as the minimum settings that are required for Azure Function runtime to start properly and communicate properly with app insights live metrics.
Hope this helps someone who, like me, hates the ever-growing mass of -Variable.Name "$(ReleaseVariableName)" items in App settings. :)
Unfortunately, at present there is no standard way to get the local running directory. It would be best if ExecutionContext or something similar exposed this.
In the absence of a standard way, I am using AzureWebJobsScriptRoot environment variable to get the current working directory, but it only works locally. In azure environment, I am using Environment.GetEnvironmentVariable("HOME")}\\site\\wwwroot.
I posted a code for this in response to a similar question here:
Azure Functions, how to have multiple .json config files
There is also a similar solution at this github issue.
You might want to use GetContext().ApplicationRootPath, for example:
[assembly:FunctionsStartup(typeof(SampleFunction.FunctionsAppStartup))]
namespace SampleFunction
{
public class FunctionsAppStartup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
string appRootPath = builder.GetContext().ApplicationRootPath;
// ...
}
}
}
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:
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