Using ConfigurationManager to load config from an arbitrary location - asp.net

I'm developing a data access component that will be used in a website that contains a mix of classic ASP and ASP.NET pages, and need a good way to manage its configuration settings.
I'd like to use a custom ConfigurationSection, and for the ASP.NET pages this works great. But when the component is called via COM interop from a classic ASP page, the component isn't running in the context of an ASP.NET request and therefore has no knowledge of web.config.
Is there a way to tell the ConfigurationManager to just load the configuration from an arbitrary path (e.g. ..\web.config if my assembly is in the /bin folder)? If there is then I'm thinking my component can fall back to that if the default ConfigurationManager.GetSection returns null for my custom section.
Any other approaches to this would be welcome!

Try this:
System.Configuration.ConfigurationFileMap fileMap = new ConfigurationFileMap(strConfigPath); //Path to your config file
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedMachineConfiguration(fileMap);

Another solution is to override the default environment configuration file path.
I find it the best solution for the of non-trivial-path configuration file load, specifically the best way to attach configuration file to dll.
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", <Full_Path_To_The_Configuration_File>);
Example:
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", #"C:\Shared\app.config");
More details may be found at this blog.
Additionally, this other answer has an excellent solution, complete with code to refresh
the app config and an IDisposable object to reset it back to it's original state. With this
solution, you can keep the temporary app config scoped:
using(AppConfig.Change(tempFileName))
{
// tempFileName is used for the app config during this context
}

Ishmaeel's answer generally does work, however I found one issue, which is that using OpenMappedMachineConfiguration seems to lose your inherited section groups from machine.config. This means that you can access your own custom sections (which is all the OP wanted), but not the normal system sections. For example, this code will not work:
ConfigurationFileMap fileMap = new ConfigurationFileMap(strConfigPath);
Configuration configuration = ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
MailSettingsSectionGroup thisMail = configuration.GetSectionGroup("system.net/mailSettings") as MailSettingsSectionGroup; // returns null
Basically, if you put a watch on the configuration.SectionGroups, you'll see that system.net is not registered as a SectionGroup, so it's pretty much inaccessible via the normal channels.
There are two ways I found to work around this. The first, which I don't like, is to re-implement the system section groups by copying them from machine.config into your own web.config e.g.
<sectionGroup name="system.net" type="System.Net.Configuration.NetSectionGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<sectionGroup name="mailSettings" type="System.Net.Configuration.MailSettingsSectionGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="smtp" type="System.Net.Configuration.SmtpSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</sectionGroup>
</sectionGroup>
I'm not sure the web application itself will run correctly after that, but you can access the sectionGroups correctly.
The second solution it is instead to open your web.config as an EXE configuration, which is probably closer to its intended function anyway:
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = strConfigPath };
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
MailSettingsSectionGroup thisMail = configuration.GetSectionGroup("system.net/mailSettings") as MailSettingsSectionGroup; // returns valid object!
I daresay none of the answers provided here, neither mine or Ishmaeel's, are quite using these functions how the .NET designers intended. But, this seems to work for me.

The accepted answer is wrong!!
It throws the following exception on accessing the AppSettings property:
Unable to cast object of type 'System.Configuration.DefaultSection' to type 'System.Configuration.AppSettingsSection'.
Here is the correct solution:
System.Configuration.ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = "YourFilePath";
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

In addition to Ishmaeel's answer, the method OpenMappedMachineConfiguration() will always return a Configuration object. So to check to see if it loaded you should check the HasFile property where true means it came from a file.

I provided the configuration values to word hosted .nET Compoent as follows.
A .NET Class Library component being called/hosted in MS Word. To provide configuration values to my component, I created winword.exe.config in C:\Program Files\Microsoft Office\OFFICE11 folder. You should be able to read configurations values like You do in Traditional .NET.
string sMsg = System.Configuration.ConfigurationManager.AppSettings["WSURL"];

For ASP.NET use WebConfigurationManager:
var config = WebConfigurationManager.OpenWebConfiguration("~/Sites/" + requestDomain + "/");
(..)
config.AppSettings.Settings["xxxx"].Value;

This should do the trick :
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "newAppConfig.config);
Source : https://www.codeproject.com/Articles/616065/Why-Where-and-How-of-NET-Configuration-Files

Use XML processing:
var appPath = AppDomain.CurrentDomain.BaseDirectory;
var configPath = Path.Combine(appPath, baseFileName);;
var root = XElement.Load(configPath);
// can call root.Elements(...)

Related

How to get the list of configSections in web.config

My ASP.NET web service has the following custom configSections defined in its web.config:
<configSections>
<section name="config1" type="MyWebService.Configuration.MyWebServiceSection, App_Code"/>
<section name="config2" type="MyWebService.Configuration.MyWebServiceSection, App_Code"/>
</configSections>
From within a WebMethod, I need to get the list of section names defined there, which in this example would be "config1" and "config2". From this answer, I learned that a standalone application can get what I'm looking for by using something like:
Configuration config = ConfigurationManager.OpenExeConfiguration(pathToExecutable);
foreach (ConfigurationSection cs in config.Sections)
{
sectionNames.Add(cs.SectionInformation.SectionName);
}
but I need to do this from inside a web service, so I don't have a path to an executable. There is a suggestion in the comments on that answer to use ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); instead of the path to the executable, but that didn't work for me either (System.Argument exception: "exePath must be specified when not running inside a stand alone exe").
Is this the right approach, and if so, what should I pass to OpenExeConfiguration when I'm running inside a web service?
For asp.net use this. You need to use WebConfigurationManager for web applications
var conf = WebConfigurationManager.OpenWebConfiguration("<path>")
foreach(var sec in conf.Sections)
{
. . . .
}
https://msdn.microsoft.com/en-us/library/system.configuration.configuration.sections%28v=vs.110%29.aspx

No owin.Environment item was found in the context

Microsoft recently introduced new ASP.NET Identity - replacement for old (Simple)Membership. Unfortunately, I can't use this new membership system in my old project because it throws System.InvalidOperationException: No owin.Environment item was found in the context. This is a known bug, but Microsoft keeps silence about this issue. The easiest way to reproduce this bug - it's to create a new web application (MVC, WebForms or WebApi - doesn't matter) in VS 2013 (with Web Tools 2013 Preview Refresh) and then go to the login page. It will work. Then change namespace in your application to anything else than original namespace and login page will throw that error. Changing namespace back to original (the one you used at the creation of a project) will solve this problem.
It looks like .net stores somewhere something related to the original namespace, but I can't find what and where, it's not in the project folder. I know that stackoverflow is not a place for a bug reports, I just hoping that someone already found a solution for this issue or maybe people involved in the development of ASP.NET Identity will see this.
Most likely it cannot find the OWIN Startup class. The default convention for the Startup class is [AssemblyName].Startup. If you're no longer following that convention you'll need to specify the full name of your Startup class in the Web.Config.
The next release of Microsoft.Owin.Host.SystemWeb package now throws detailed exception messages when the Startup class cannot be found.
I had the same issue, it was fixed after making sure this line was in web.config:
<add key="owin:AutomaticAppStartup" value="true" />
I had the exact same error, but as it turned out I had another configuration problem in my web.config. My web.config was missing the attribute defaultLanguage="c#" in the compilation element under system.web.
In this case it will default to VB. So unless you have your Startup class written in VB you should change the default language to C#.
Not correct:
<compilation debug="true" optimizeCompilations="true" targetFramework="4.6.1">
This is correct (unless you use VB):
<compilation debug="true" defaultLanguage="c#" optimizeCompilations="true" targetFramework="4.6.1">
Cleaning ASP.NET temporary files helped me with this exact problem
I created two new projects called TesteMvc5.2 and TesteMvc5.0 and both of them didn't work at start
this is because the default namespace is different from the assembly name.
but after I put the line
<add key="owin:AppStartup" value="TesteMvc5._2.Startup, TesteMvc5.2" />
on the web.config it worked fine.
I tried everything mentioned on this page but nothing worked. Then I found out about a setting in IIS named owin:AutomaticAppStartup. You can find it in the Application Settings page of the IIS Manager for the Default Web Site. Check to see if that setting is true. If not set to true. This worked for me.
This is the website where I found the answer:
http://gotoanswer.stanford.edu/?q=Microsoft.Owin.Host.SystemWeb+and+still+getting+No+owin.Environment+item+was+found+in+the+context
If you happened to have copied the below config from MVC4, you should remove it from web.config
<add key="owin:AutomaticAppStartup" value="false" />
I had this same issue. I fixed it with the web.config.
However I had changed the assembly name and namespace and did not find the original assembly name anywhere anymore.
I then discovered that clean was not removing the original assembly from the bin.
Aftter deleting the bin litter, I was able to remove the web.config OWIN entry.
None of the above answers worked for me.
Turned out my project was missing the "Startup" class that contains the following:
using Microsoft.Owin;
using Owin;
[assembly: OwinStartupAttribute(typeof(NAMESPACE.Startup))]
namespace NAMESPACE
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
}
This file called "Startup.cs" is located on the root folder (~/) of your project.
My "Web.config" doesn't have any of this "Owin" configuration posted on the other replies.
Had same problem. Thanks for the shared solutions.
this..
<add key="owin.AppStartup" value="Namespace.Startup, Namespace"/>
<add key="owin:AutomaticAppStartup" value="false"/>
fixed for me
I have no idea why this works but it did!
My problem was in VS2013. In the WebConfig, debug was set to true and I got that error. When I set it to false it worked fine and then I reset to true and it continued to work OK!
At first when debug was true before changing to false, I put a break point in my StartUp code and it wasn't reached at all. After changing to false pressing save and then back to true the StartUp code was called and the program works like it should.
I experienced this error in an Optimizely (Episerver) solution where I had two feature branches using the same CMS database. In one feature branch I was working on a proof of concept using a visitor criterion. So I had created something like this:
public class SomeVisitorCriterionSettings : CriterionModelBase
{
public override ICriterionModel Copy()
{
return base.ShallowCopy();
}
}
[VisitorGroupCriterion(
Category = "Some category",
DisplayName = "My visitor criterion")]
public class SomeVisitorCriterion : CriterionBase<SomeVisitorCriterionSettings>
{
public override bool IsMatch(IPrincipal principal, HttpContextBase httpContext)
{
// match logic here..
}
}
And within Episerver -> CMS -> Visitor Groups I had created an instance of this visitor criterion. After switching to the other branch where this code did not exist, but the instance in the database did, the Owin exception was thrown.
Deleting the visitor criterion in the CMS resolved the issue, but I honestly have no idea why this sort of exception is thrown. I would love to know though..
I have tried all of the above suggestions, without success;
then reading the documentation at:
https://learn.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-startup-class-detection
I understood that the error was in the call to the assembly in the Startup.cs file:
wrong code:
[assembly: OwinStartupAttribute(typeof([AssemblyName].Startup))]
right code:
[assembly: OwinStartup(typeof([AssemblyName].Startup))]
so, I fixed the error removing the word Attribute from OwinStartupAttribute
adding default language to compilation in web.config did it for me!

Adding Assembly to ASP.Net website

I want to use the Task Scheduler Managed Wrapper in my ASP.Net project so that I can access the windows task scheduler from within my website. From what I have learned so far I need to add a reference to the assembly dll to my web.config. is that right? How do I figure out the public key token for the assembly file though? Is there any other way than using the 'sn.exe' utility, because I don't have the .net SDK installed and I unfortunately have no option of doing so on this computer. Thank you for your help!!
You shouldn't have to do anything with sn.exe or the public key token.
If you are working in a Web Site, right click your web-site in the Solution Explorer and click "Add Reference". It will create a Bin folder for you if there isn't one, then add the assembly to the bin.
If you are working in a Web Application, use the Add Reference dialog by right clicking "References" in the solution explorer.
EDIT:
thank you but i am not using visual studio at all. all i have is IIS and I use notepad for editing. the server side portion of my website is written in jscript.net
You will probably be adding a Reference with the web.config then, such as:
<system.web>
<assemblies>
<add assembly="YourAssemblyNameInBin" />
</assemblies>
</system.web>
Place your assembly in the Bin, and change YourAssemblyNameInBin to the name of the assembly on disk without the extension.
You don't have to include the version, culture, and public key token of the assembly. If you want to though, you can use the sn.exe tool to display the public key token like so:
sn.exe -T "PathToAssembly"
Note that the T is capital. If the assembly is not signed - then you must omit the public key token from the reference.

How do you modify the web.config appSettings at runtime?

I am confused on how to modify the web.config appSettings values at runtime. For example, I have this appSettings section:
<appSettings>
<add key="productspagedesc" value="TODO: Edit this default message" />
<add key="servicespagedesc" value="TODO: Edit this default message" />
<add key="contactspagedesc" value="TODO: Edit this default message" />
<add key="aboutpagedesc" value="TODO: Edit this default message" />
<add key="homepagedesc" value="TODO: Edit this default message" />
</appSettings>
Let's say, I want to modify the "homepagedesc" key at runtime. I tried ConfigurationManager and WebConfigurationManager static classes, but the settings are "read-only". How do I modify appSettings values at runtime?
UPDATE:
Ok, so here I am 5 years later. I would like to point out that experience has told me, we should not put any configuration that intentionally is editable at runtime in the web.config file but instead we should put it in a separate XML file as what one of the users commented below. This will not require any of edit of web.config file to restart the App which will result with angry users calling you.
You need to use WebConfigurationManager.OpenWebConfiguration():
For Example:
Dim myConfiguration As Configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~")
myConfiguration.ConnectionStrings.ConnectionStrings("myDatabaseName").ConnectionString = txtConnectionString.Text
myConfiguration.AppSettings.Settings.Item("myKey").Value = txtmyKey.Text
myConfiguration.Save()
I think you might also need to set AllowLocation in machine.config. This is a boolean value that indicates whether individual pages can be configured using the element. If the "allowLocation" is false, it cannot be configured in individual elements.
Finally, it makes a difference if you run your application in IIS and run your test sample from Visual Studio. The ASP.NET process identity is the IIS account, ASPNET or NETWORK SERVICES (depending on IIS version).
Might need to grant ASPNET or NETWORK SERVICES Modify access on the folder where web.config resides.
Changing the web.config generally causes an application restart.
If you really need your application to edit its own settings, then you should consider a different approach such as databasing the settings or creating an xml file with the editable settings.
And if you want to avoid the restart of the application, you can move out the appSettings section:
<appSettings configSource="Config\appSettings.config"/>
to a separate file. And in combination with ConfigurationSaveMode.Minimal
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
config.Save(ConfigurationSaveMode.Minimal);
you can continue to use the appSettings section as the store for various settings without causing application restarts and without the need to use a file with a different format than the normal appSettings section.
2012
This is a better solution for this scenario (tested With Visual Studio 2008):
Configuration config = WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath);
config.AppSettings.Settings.Remove("MyVariable");
config.AppSettings.Settings.Add("MyVariable", "MyValue");
config.Save();
Update 2018 =>
Tested in vs 2015 - Asp.net MVC5
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
config.AppSettings.Settings["MyVariable"].Value = "MyValue";
config.Save();
if u need to checking element exist, use this code:
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
if (config.AppSettings.Settings["MyVariable"] != null)
{
config.AppSettings.Settings["MyVariable"].Value = "MyValue";
}
else { config.AppSettings.Settings.Add("MyVariable", "MyValue"); }
config.Save();
I know this question is old, but I wanted to post an answer based on the current state of affairs in the ASP.NET\IIS world combined with my real world experience.
I recently spearheaded a project at my company where I wanted to consolidate and manage all of the appSettings & connectionStrings settings in our web.config files in one central place. I wanted to pursue an approach where our config settings were stored in ZooKeeper due to that projects maturity & stability. Not to mention that fact that ZooKeeper is by design a configuration & cluster managing application.
The project goals were very simple;
get ASP.NET to communicate with ZooKeeper
in Global.asax, Application_Start - pull web.config settings from ZooKeeper.
Upon getting passed the technical piece of getting ASP.NET to talk to ZooKeeper, I quickly found and hit a wall with the following code;
ConfigurationManager.AppSettings.Add(key_name, data_value)
That statement made the most logical sense since I wanted to ADD new settings to the appSettings collection. However, as the original poster (and many others) mentioned, this code call returns an Error stating that the collection is Read-Only.
After doing a bit of research and seeing all the different crazy ways people worked around this problem, I was very discouraged. Instead of giving up or settling for what appeared to be a less than ideal scenario, I decided to dig in and see if I was missing something.
With a little trial and error, I found the following code would do exactly what I wanted;
ConfigurationManager.AppSettings.Set(key_name, data_value)
Using this line of code, I am now able to load all 85 appSettings keys from ZooKeeper in my Application_Start.
In regards to general statements about changes to web.config triggering IIS recycles, I edited the following appPool settings to monitor the situation behind the scenes;
appPool-->Advanced Settings-->Recycling-->Disable Recycling for Configuration Changes = False
appPool-->Advanced Settings-->Recycling-->Generate Recycle Event Log Entry-->[For Each Setting] = True
With that combination of settings, if this process were to cause an appPool recycle, an Event Log entry should have be recorded, which it was not.
This leads me to conclude that it is possible, and indeed safe, to load an applications settings from a centralized storage medium.
I should mention that I am using IIS7.5 on Windows 7. The code will be getting deployed to IIS8 on Win2012. Should anything regarding this answer change, I will update this answer accordingly.
Who likes directly to the point,
In your Config
<appSettings>
<add key="Conf_id" value="71" />
</appSettings>
in your code(c#)
///SET
ConfigurationManager.AppSettings.Set("Conf_id", "whateveryourvalue");
///GET
string conf = ConfigurationManager.AppSettings.Get("Conf_id").ToString();
Try This:
using System;
using System.Configuration;
using System.Web.Configuration;
namespace SampleApplication.WebConfig
{
public partial class webConfigFile : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//Helps to open the Root level web.config file.
Configuration webConfigApp = WebConfigurationManager.OpenWebConfiguration("~");
//Modifying the AppKey from AppValue to AppValue1
webConfigApp.AppSettings.Settings["ConnectionString"].Value = "ConnectionString";
//Save the Modified settings of AppSettings.
webConfigApp.Save();
}
}
}

Webpart registration error in event log

We created several custom web parts for SharePoint 2007. They work fine. However whenever they are loaded, we get an error in the event log saying:
error initializing safe control - Assembly: ...
The assembly actually loads fine. Additionally, it is correctly listed in the web.config and GAC.
Any ideas about how to stop these (Phantom?) errors would be appreciated.
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
You need to add a safecontrol entry to the web,config file, have a look at the following:
<SafeControls>
<SafeControl
Assembly = "Text"
Namespace = "Text"
Safe = "TRUE" | "FALSE"
TypeName = "Text"/>
...
</SafeControls>
http://msdn.microsoft.com/en-us/library/ms413697.aspx
I was having this problem too. It turned out that there was a problem with my Manifest.xml file. In the SafeControl tag for my assembly, I had the TypeName specifically defined. When I changed the TypeName to a wildcard value, the error messages in the event log stopped.
So to recap:
This caused errors in the event log:
<SafeControl Assembly="AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5bac12230d2e4a0a" Namespace="AssemblyName" **TypeName="AssemblyName"** Safe="True" />
This cleared them up:
<SafeControl Assembly="AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5bac12230d2e4a0a" Namespace="AssemblyName" **TypeName="*"** Safe="True" />
It sure does sound like you have a problem with your safe control entry. I would try:
Under the NameSpace and TypeName use "*". Using wildcards in namespace and typeName will register all classes in all namespaces in your assembly as safe. (You generally wouldn't want to do this with 3rd party tools.)
This is because of the amount of list items in the lists. Your server takes to much time to migrate all the list items and it fails, try deleiting the list items or configuring the server.
Regards,
Mariano.

Resources