I need to disable Local Authentication Methods (Access Keys) for Azure App Configuration Stores.
Currently for an ASP.NET Framework application, I am using the following for accessing the App Configuration Store from my application:
<configSections>
<section name="configBuilders" type="System.Configuration.ConfigurationBuildersSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" restartOnExternalChanges="false" requirePermission="false" />
</configSections>
<configBuilders>
<builders>
<add name="MyConfigStore" mode="Greedy" connectionString="${ConnectionString}" type="Microsoft.Configuration.ConfigurationBuilders.AzureAppConfigurationBuilder, Microsoft.Configuration.ConfigurationBuilders.AzureAppConfiguration" />
<add name="Environment" mode="Greedy" type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Environment" />
</builders>
</configBuilders>
Here the value of ${ConnectionString} = "Endpoint=https://<app_config>.azconfig.io;Id=<Id>;Secret=<Access Key>"
Now in order to access the App Configuration through the ASP.NET application, I created a Service Principal, generated a secret to use.
I have stored the CLIENT_ID, TENANT_ID and CLIENT_SECRET values. I have also assigned the App Configuration Data Reader role to the Service Principal.
I also have a managed identity which I can use.
Now what change do I need to make at the application side in order to access the App Configuration through the ASP.NET application?
You should use the endpoint instead of the connectionString parameter when you config your builders. This will tell the system to use the DefaultAzureCredential to connect to Azure App Configuration.
I would also put the "Environment" builder before the "AzureAppConfig" builder, so environment variables are available to the AppConfig builder during loading. It looks something like this:
<configBuilders>
<builders>
<add name="Environment" mode="Greedy" type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Environment" />
<add name="AzureAppConfig" mode="Greedy" endpoint="https://<AppConfigName>.azconfig.io" type="Microsoft.Configuration.ConfigurationBuilders.AzureAppConfigurationBuilder, Microsoft.Configuration.ConfigurationBuilders.AzureAppConfiguration" />
</builders>
</configBuilders>
Given you want to use the service principal, you should make CLIENT_ID, TENANT_ID and CLIENT_SECRET available as environment variables, so the DefaultAzureCredential will pick them up automatically.
You should NEVER put any secrets in the web.config file. You can find more information about the App Configuration builder library from the link below.
https://github.com/aspnet/MicrosoftConfigurationBuilders/blob/main/docs/KeyValueConfigBuilders.md#azureappconfigurationbuilder
Check the below Workaround to access the App Configuration in the .NET Framework Application.
In Azure Portal => App Configuration => Configuration explorer,
create new Key-value.
Install the below NuGet Packages
Microsoft.Configuration.ConfigurationBuilders.AzureAppConfiguratio - Version 1.0.0
Microsoft.Configuration.ConfigurationBuilders.Environment - Version 2.0.0
System.Configuration.ConfigurationManager - Version 7.0.0
Configuration Section from my Web.config file:
<configSections>
<section name="configBuilders" type="System.Configuration.ConfigurationBuildersSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" restartOnExternalChanges="false" requirePermission="false" />
</configSections>
<configBuilders>
<builders>
<add name="AzureAppConfig" mode="Greedy" connectionString="Endpoint=https://AppConfigName.azconfig.io;Id=XqdS-l2-s0:****/;Secret=****" type="Microsoft.Configuration.ConfigurationBuilders.AzureAppConfigurationBuilder, Microsoft.Configuration.ConfigurationBuilders.AzureAppConfiguration" />
<add name="Environment" mode="Greedy" type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Environment" />
</builders>
</configBuilders>
<appSettings configBuilders="Environment,AzureAppConfig">
<add key="AppName" value=".NET Framework Sample" />
</appSettings>
Reading Config Value:
In Controller,
public ActionResult Index()
{
string FromAppConfig = System.Configuration.ConfigurationManager.AppSettings["TestApp:Settings:Message"];
string FromWebConfig = System.Configuration.ConfigurationManager.AppSettings["AppName"];
ViewBag.FromAppConfig = FromAppConfig;
ViewBag.FromWebConfig = FromWebConfig;
return View();
}
In View.cshtml:
#{
ViewBag.Title = "Home Page";
}
<div>
<h2> Value from App Configuration - #ViewBag.FromAppConfig</h2>
<h2> Value from Web.Config File - #ViewBag.FromWebConfig</h2>
</div>
OutPut:
References taken from MSDoc
Related
I have learnt about custom configurations using the ConfigurationManager. For some reason you have to use the assembly reference in the section element of the app.config, otherwise the ConfigurationManager won't load the app.config. But in an ASP.NET app this works fine. Why?
Consider this custom configuration class:
namespace CustomConfiguration
{
class MySection : ConfigurationSection
{
[ConfigurationProperty("link", IsKey = true)]
public string Link
{
get => (string) this["link"];
set => this["link"] = value;
}
}
}
Using this app.config, I can easily get the link-attribute of myCustomSection in my program:
<configuration>
<configSections>
<section name="myCustomSection" type="CustomConfiguration.MySection, myAssembly" />
</configSections>
...
<myCustomSection link="link i can access in my code" >
</myCustomSection>
</configuration>
Removing the assembly reference in section-element of app.config will result in a ConfigurationErrorsException, because the ConfigurationManager can't load my CustomConfiguration.MySection class in it's own System.Configuration assembly.
E.g.:
<section name="myCustomSection" type="CustomConfiguration.MySection" />
But Microsofts documentation says I should be able to do this.
And in fact I can do this in an ASP.NET app. Not supplying an assembly-name in a type attribute for a section still works and system.configuration magically looks in the right app assembly. Why?
The ASP.NET hosting environment has a different assembly loading behaviour;
it loads all referenced assemblies (from then bin and GAC) at the moment of startup.
For that reason, the assembly of the CustomConfiguration.MySection section can be resolved automatically without specifying it in the type definition.
If you include the settings below in you web.config file, your assembly myAssembly will not be loaded at initial startup anymore.
Then it will also be required to specify the assembly part in the type definition via CustomConfiguration.MySection, myAssembly. Here you get the same behaviour as in a non web-based application.
<configuration>
<!-- ... -->
<system.web>
<compilation>
<assemblies>
<remove assembly="myAssembly" />
</assemblies>
</compilation>
</system.web>
<!-- ... -->
</configuration>
The referenced documentation in your question shows that a section (shown belown) can be declared in an app.config file (of non web-based application), but this will only work for the out-of-the-box supplied configuration classes/handlers, like eg. System.Configuration.SingleTagSectionHandler, which resides in the core System assemby (System.dll).
For all other (custom) sections, a full assembly-qualified name is required.
<configuration>
<configSections>
<section name="sampleSection"
type="System.Configuration.SingleTagSectionHandler" />
</configSections>
<sampleSection setting1="Value1"
setting2="value two"
setting3="third value" />
</configuration>
I'm developing a WinForm application with C# and .NET Framework 4.7.
I want to open a Web.config file, read its appSetting section and modify it.
To open it, I use this:
System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration(null);
It opens it but, when I try to get the keys with:
string[] keys = config.AppSettings.Settings.AllKeys;
I get a null array.
This is the appSetting section:
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<connectionStrings>
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="MinRemainingCodes" value="100" />
<!-- Others keys -->
</appSettings>
</configuration>
Maybe the problem is that it is not opening the file, but in the documentation say:
The virtual path to the configuration file. If null, the root
Web.config file is opened.
Maybe I don't understand what means with root because the program and the Web.config file are in the same folder.
What am I doing wrong?
WebConfigurationManager.OpenWebConfiguration includes the following description of the path parameter:
The virtual path to the configuration file. If null, the root Web.config file is opened.
Because your application is not running under IIS as a Web Site, the Web.config that is being opened is actually that which lives in the .NET Framework installation folder itself (in my case, that's C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\web.config).
WebConfigurationManager.OpenMappedWebConfiguration allows you to map virtual directories to physical directories in order to allow you to specify a virtual path that is mapped to your own local directory. Here's the code I've used to make this work:
var webConfigurationFileMap = new WebConfigurationFileMap();
webConfigurationFileMap.VirtualDirectories.Add(
string.Empty,
new VirtualDirectoryMapping(Directory.GetCurrentDirectory(), isAppRoot: true));
var webConfig = WebConfigurationManager.OpenMappedWebConfiguration(
webConfigurationFileMap,
string.Empty);
As you can see, I'm mapping the root virtual directory (using string.Empty) to the application's directory (using Directory.GetCurrentDirectory).
OpenWebConfiguration is supposed to receive the path to your web config if I'm not mistaken and you are passing it null.
Try like this:
config = WebConfigurationManager.OpenWebConfiguration("~");
Also this might help you: How do you modify the web.config appSettings at runtime?
Well, first of all, you use web.config for a desktop application. It doesn't sound correct. Try to use app.config instead.
Second, WebConfigurationManager.OpenWebConfiguration opens the Web-application configuration file
As for the topic, to get information from the config file try to use
var keys = ConfigurationManager.AppSettings.AllKeys
Well I have following entries in my web config for SagePay Integration in an ASP.net MVC project.
<configuration>
<configSections>
<section name="SagePayConfiguration" type="System.Configuration.IgnoreSectionHandler" requirePermission="true" restartOnExternalChanges="true" allowLocation="true"/>
</configSections>
<SagePayConfiguration>
<!--Mandatory
Set to TEST for the Test Server and LIVE for the live environment-->
<add key="sagepay.api.env" value="TEST" />
.
.
</SagePayConfiguration>
However I am getting null when trying to access it from C# code.
SagePayConfiguration sagePayConfiguration = (SagePayConfiguration)System.Configuration.ConfigurationManager.GetSection("SagePayConfiguration");
Any help what I am missing here?
You must cast the ConfigrationItem to "System.Configuration.IgnoreSectionHandler" or set the type Attribute in web.conf to an existing Type in your assembly.
<section name="<SectionName>" type="<your type (FQN)>, <Assembly>" />
After that you can access it
YourType o = ((YourType)ConfigurationManager.GetSection("sectionName"));
EDIT:
The Type must derive from ConfigurationSection.
I have win 2008 R2 server with .net mvc project and other Ubuntu Linux with memchaed installed.
I have Eniym Memcached connector to memcached.
But when I try to run any memcached query I get:
An error occurred creating the configuration section handler for enyim.com/memcached: Could not load type 'e.Caching.Configuration.MemcachedClientSection' from assembly 'Enyim.Caching'.
Enyim web.config section:
<configSections>
<sectionGroup name="enyim.com">
<section name="memcached" type="e.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
</sectionGroup>
</configSections>
<enyim.com>
<memcached>
<servers>
<add address="10.10.10.10(not real ip, connect to other server)" port="11222" />
</servers>
<socketPool deadTimeout="00:00:10" />
</memcached>
</enyim.com>
Controller action:
using Enyim.Caching;
using Enyim.Caching.Memcached;
public string About()
{
MemcachedClient memCache = new MemcachedClient();
memCache.Store(StoreMode.Set, "testkey", "testcontent");
return "some string";
}
Where can be the problem?
There's a good example here.
I think you want "Enyim.Caching.Configuration.MemcachedClientSection" where you currently have "e.Caching.Configuration.MemcachedClientSection"
I've tried updating my application's .config file during installer (via a .NET Installer Class Action). But, I can't seem to get ConfigurationManager to list any properties or be able to set anything.
I learned of this approach from several stackoverflow posts that pointed me to this guide: http://raquila.com/software/configure-app-config-application-settings-during-msi-install/
I've investigated the differences between my project and his and noticed that my configuration files are formatted differently. I believe this has to do with the fact that i'm using "Settings" files.
Config files formatted in the guide look like:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Param1" value="" />
<add key="Param2" value="" />
<add key="Param3" value="" />
</appSettings>
</configuration>
Where mine looks like:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="MyAppName.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
<section name="MyAppName.Settings1" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="MyAppName.Settings1" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<MyAppName.Properties.Settings>
<setting name="TESTSETTING" serializeAs="String">
<value>asdfasdfasdf</value>
</setting>
</MyAppName.Properties.Settings>
<MyAppName.Settings1>
<setting name="VerboseErrorMode" serializeAs="String">
<value>False</value>
</setting>
<applicationSettings>
<MyAppName.Settings1>
<setting name="RunOnStartup" serializeAs="String">
<value>True</value>
</setting>
</MyAppName.Settings1>
</applicationSettings>
</configuration>
To shed some light on what was going on... I tried printing out the list of settings like so:
Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);
// Try getting the Settings1 Section
AppSettingsSection appSettings = (AppSettingsSection)config.GetSection("Settings1"); // Also tried myNamespace.Settings1
if (appSettings != null)
{
valList = "Settings1: ";
foreach (string key in appSettings.Settings.AllKeys)
{
string value = appSettings.Settings[key].Value;
valList += ("Key: '" + key + "' = '" + value + "'\n");
}
}
else
{
valList = "appSettings was null";
}
MessageBox.Show(valList);
MessageBox.Show(valList);
I have tried several permutations of this... and in all cases output is "appSettings was null".
I also tried initializing the configuration manager in several different ways...
Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);
MessageBox.Show("Section Count: " + config.Sections.Count);
MessageBox.Show("Has File: " + config.HasFile);
MessageBox.Show("Namespace Declared: " + config.NamespaceDeclared);
config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
MessageBox.Show("Section Count: " + config.Sections.Count);
MessageBox.Show("Has File: " + config.HasFile);
MessageBox.Show("Namespace Declared: " + config.NamespaceDeclared);
For each of them the section count returned was 20. (I have no idea where the 20 comes from... I would have expected it to be 3).
HasFile was true for the first case and false for the second.
Namespace Declared was false in both cases.
Thanks!
EDIT (6-18-09): Still looking into this question. Anyone else have any ideas? Thanks.
Search Keywords: "Object Reference Not Set to not set to an instance" <-- this occurs when trying to write to a property.
I came across the same problem, after deep investigation, I found out the easiest way to update any part of config files (e.g. app.config), that's by using XPath.
We have an application which connects to web service, during the installation, the user enters the URL of the web service and this should be saved in the following app.config file:
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="ApplicationServer.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<ApplicationServer.Properties.Settings>
<setting name="ApplicationServer_ApplicationServerUrl" serializeAs="String">
<value>whatever comes from setup should go here</value>
</setting>
</ApplicationServer.Properties.Settings>
</applicationSettings>
</configuration>
Here is the code to do this in the installer class:
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
string targetDirectory = Context.Parameters["targetdir"];
string param1 = Context.Parameters["param1"];
string path = System.IO.Path.Combine(targetDirectory, "app.config");
System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
xDoc.Load(path);
System.Xml.XmlNode node = xDoc.SelectSingleNode("/configuration/applicationSettings/Intellisense.ApplicationServer.Properties.Settings/setting[#name='ApplicationServer_ApplicationServerUrl']/value");
node.InnerText = (param1.EndsWith("/") ? param1 : param1 + "/");
xDoc.Save(path); // saves the web.config file
}
Basically, since the config file is a XML based document, I am using XPath expression to locate specific node and change its value.
One thing to try is moving it from install to Commit to ensure that the file has been written first before trying to access it. Alternatively you could use the custom action to write your own file and just alter your config file to point at the alternative xml file.
I worked on a Sharepoint product install where I dug into all of this and I will admit it is very tedious to get working correctly. I was creating config and batch files on the fly based on install parameters.
You can access these settings using the System.Configuration namespace but, its not as simple as I would like and in retrospect using System.Xml.Linq is far simpler. Anyway, here is how I got it to work.
The important concept is, the applicationSettings section is not AppSettings, its a seperate section supported by the ClientSettingsSection type.
//Open the application level config file
ExeConfigurationFileMap exeMap = new ExeConfigurationFileMap();
exeMap.ExeConfigFilename = String.Format("{0}.config",
Context.Parameters["assemblypath"]);
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(exeMap,
ConfigurationUserLevel.None);
//Get the settings section
ClientSettingsSection settingsSection =
config.GetSectionGroup("applicationSettings").Sections
.OfType<ClientSettingsSection>().Single();
//Update "TheSetting"
//I couldn't get the changes to persist unless
//I removed then readded the element.
SettingElement oldElement = settingsSection.Get("TheSetting");
settingsSection.Settings.Remove(oldElement);
SettingElement newElement = new SettingElement("TheSetting",
SettingSerializeAs.String);
newElement.Value = new SettingValueElement();
newElement.Value.ValueXml = oldElement.Value.ValueXml.CloneNode(true);
newElement.Value.ValueXml.InnerText = "Some New Value";
settingsSection.Add(newElement);
//Save the changes
config.Save(ConfigurationSaveMode.Full);
So, as you can see, simple. :-S
Instead of accessing your settings configuration via ConfigurationManager, you should be able to access it via Settings.Default. Settings are more of a Visual Studio feature than a .NET feature...a convenience that makes it easy to visually design your applications configuration rather than manually writing it in appSettings or creating custom configuration sections. However, the configuration schema that is rendered when you use Settings is non-standard, and can be difficult to access manually.
Visual Studio should have generated a Settings class for you when you built your application, and you should be able to access that class via Properties.Settings.Default. It should have a property for each setting, in your case, the following:
Properties.Settings.Default.TESTSETTING
Properties.Settings.Default.VerboseErrorMode
Properties.Settings.Default.RunOnStartup
You should be able to both read and write these settings. A critical thing to note...anything flagged as a "user" setting will not be written back to the {yourapplication}.exe.config file...it will be written to a User.config file in the users isolated profile storage area. This is under C:\Documents and Settings{username} on XP, and C:\Users{username} on Vista, in the AppData folder. Depending on the OS and users profile, the subfolder under the AppData may change, but its completely unique and keyed to a particular version of the application. Installation of a newer version will result in a completely new set of configuration settings stored under the same keyed folder, but a different version subfolder.
I hope this helps. :)
This is what you need: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/f89a00eb-9400-48ce-af20-cef78002c14e