Intro:
Normally we store ConnectionStrings and some other settings (<appSettings> <add key...) in the Web.config or App.config.
My scenery:
Web application using factory pattern
with direct injection to read data
providers.
In the web.config I have the key
that tells me which DLL (provider)
will I use to retrieve my data.
I can have more than one provider
(each DLL will be a provider for MS
SQL, MySQL, or get the data from
some SOA service).
Each DLL has his own name (ID and namespaces) and will need to have is own
configurations (dataconnections,
service urls, etc...) , the first
idea is to write then in the
app.config.
Problems:
#1 - The website is running (runtime) I need to change the Data Provider, how can I do this? Somehow the default value written in the Web.config will be changed.
My objective is to be able to have multiple providers (and during runtime: add/delete providers and change configurations) - this leads me to my second problem:
.
#2 - Each Data Provider has custom configurations and App.Config files do not work with dll assemblies, only executables. This means that I need to write then on my Web.Config (I do not like this option, because once again I am updating my web.config in runtime). how can I solve this?
I am trying to avoid to write a custom settings XML file. My ideal solution is to deploy somehow the DLL and DLL.config per each provider. And once again during runtime I may need to change this configuration values.
.
Ok guys, while I was waiting for some help I put my hands to work and I was able to find a good solution (in my opinion of course :P).
Let me share it with you:
So, I have one web application, or one console application, or some other kind of application, and lots of class library, and I need to store informations (different per Visual Studio project) that will change during runtime.
Storing this information inside the Web.config or App.config is not a good idea for the many problems it takes.
The other way I see it is to have one XML config file per project.
Each application will read his own XML and add it to the Cache with CacheDependency (will expire when the XML config file is updated). This way we will not need to read the configuration all the times, and we also know when the configuration is changed.
IMO THIS IS THE FASTEST AND EASIEST WAY TO SOLVE THE PROBLEM, no need to use 3rd party frameworks (neither the time it takes to learn/program it).
.
Example code:
protected void Page_Load(object sender, EventArgs e)
{
DBConfiguration cachConf;
cachConf = Cache["cachConf"] as DBConfiguration;
if (cachConf == null)
{
cachConf = new DBConfiguration();
XmlDocument doc = new XmlDocument();
doc.Load(HttpContext.Current.Request.PhysicalApplicationPath + "bin/MyConf.xml");
XmlNodeList xnl = doc.GetElementsByTagName("username");
XmlElement xe = (XmlElement)xnl[0];
cachConf.Username = xe.InnerText.ToString();
xnl = doc.GetElementsByTagName("password");
xe = (XmlElement)xnl[0];
cachConf.Password = xe.InnerText.ToString();
Cache.Insert("cachConf", cachConf,
new System.Web.Caching.CacheDependency(
HttpContext.Current.Request.PhysicalApplicationPath + "MyConf.xml"),
DateTime.Now.AddMinutes(60), TimeSpan.Zero,
System.Web.Caching.CacheItemPriority.Default,
new System.Web.Caching.CacheItemRemovedCallback(
CacheItemRemovedCallBack));
}
LabelUsername.Text = cachConf.Username;
LabelPassword.Text = cachConf.Password;
}
private void CacheItemRemovedCallBack(string key, object value, CacheItemRemovedReason reason)
{
//Response.Write("Hello world");
}
You could store the credentials in a secondary config file referenced from web.config as follows:
<appSettings file="AppSettings.config"/>
You would still need to be careful to avoid editing conflicts on the external file.
Problem 1 - Runtime changes:
The solution that Microsoft hopes you apply to this type of problem is to simply keep the web server stateless. When an ASP.NET application recycles, it lets existing requests complete new requests start on a new process. For background, read about IIS Process Recycling. A change to web.config recycle the worker process, but users will not notice this (unless you keep state in the web server process). That's the MS design.
If you want to monitor for changes without recycling a process, you'll want something other than default web.config behavior. An example that comes to mind are cruise controls project files. They have a component that maps objects to and from xml, using that, you can use the FileSystemWatcher class to monitor for changes.
Problem 2 - Custom configurations:
It sounds like you have components from different libraries that have different dependencies. Your main assembly needs a means to instantiate a service, with a given set of dependencies. The MS data provider model is cool, but not this cool.
To be this cool, use an inversion of control container, because this is exactly what they do. I like autofac (because I like the Philip K Dick reference), but castle windsor is great.
Now, if you are talking about changes databases or data providers on the fly, it may be that configuration is not the right place. If your are reporting against x databases of y types, you need a central repository of that database information, and a configuration file is not the right place, nor is an IOC container the right solution.
As Precipitous suggested, try Castle Windsor:
http://www.castleproject.org/container/
You're doing Inversion of Control manually. Windsor will take the burden off of you.
Related
I am looking for a way to handle this challenge: we are a geographically dispersed dev team using ASP.NET Web API and Angular to build a web app.
The thing that causes the grief is the fact that not all team members use the same database setup for their dev work. Yes, I know - I can use web.config transforms to set the proper connection strings for test, staging and production (and I'm already doing this) - but this is not what I'm talking about.
Due to reasons beyond our control at this time, we have
some developers working on a local SQL Server instance using server=(local);database=OurDB as their connection string
other developers using a central developer SQL Server in their location, using something like server=someserver.mycorp.com;database=OurDB
and a few exotic cases with yet other settings
Now every time someone commits a change to the Git repo, and happens to also change something in the web.config, his connection string is committed to the repo. So when I then go pull that latest commit, my settings to my local DB server are overwritten by this other guy's settings.
I am looking for a way to handle this - I was hoping I might be able to
hook into the Git pull process and automagically update the web.config connection string to my local needs whenever I pull something
somehow reference a connection string (or external config file) based on e.g. my currently logged in user's name or something like that
But I can't seem to find any way of doing this. I was wondering if I need to build a VS extension to handle this - any starters for that? Has anyone done something like this before and could share his code? (or has it up on Github)
The web.config configuration system used in ASP.NET is not flexible enough to support the more advanced scenario you have described. So, why use it? You could store the configuration in files within the repository, one per developer. Or they could be stored outside the repository or otherwise ignored.
The real trick is that most older applications don't have a single root that retrieve the configuration, so you have to refactor your application to utilize a flexible configuration system. For your staging/production environments you probably still want to use the config in web.config. The following code can give you a basic idea of one way to structure it:
public class MyApplicationConfiguration
{
public string MainConnectionString { get; set; }
}
public class ConfigurationRetriever
{
public MyApplicationConfiguration GetConfiguration()
{
// You might look for the absence or presence of an environment variable to determine this
bool isLocalDevelopment = IsApplicationLocalDevelopment();
var config = new MyApplicationConfiguration();
if(isLocalDevelopment)
{
config.MainConnectionString = Environment.GetEnvironmentVariable("MyApplication_MainConnectionString");
//or get it from a JSON file or XML file or config database
}
else
{
config.MainConnectionString = ConfigurationManager.ConnectionStrings["MainConnectionString"].ConnectionString;
}
}
}
Rather than rolling your own config building logic, you might refactor your application to leverage Microsoft.Extensions.Configuration. It's not just for .NET Core. It's for .NET Standard. So you can use it even in your legacy ASP.NET applications. For reading the web.config, you could probably use Microsoft.Extensions.Configuration.Xml. Or you can write your own adapter that pulls values out of ConfigurationManager. I did a basic test, and this worked as expected.
Folks,
I have an ASP.NET project which is pretty n-tier, by namespace, but I need to separate into three projects: Data Layer, Middle Tier and Front End.
I am doing this because...
A) It seems the right thing to do, and
B) I am having all sorts of problems running unit tests for ASP.NET hosted assemblies.
Anyway, my question is, where do you keep your config info?
Right now, for example, my middle tier classes (which uses Linq to SQL) automatically pull their connection string information from the web.config when instantiating a new data context.
If my data layer is in another project can/should it be using the web.config for configuration info?
If so, how will a unit test, (typically in a separate assembly) provide soch configuration info?
Thank you for your time!
We keep them in a global "Settings" file which happens to be XML. This file contains all the GLOBAL settings, one of which is a connection string pointing to the appropriate server as well as username and password. Then, when my applications consume it, they put the specific catalog (database) they need in the connection string.
We have a version of the file for each operating environment (prod, dev, staging, etc). Then, with two settings -- file path (with a token representing the environment) and the environment -- I can pick up the correct settings files.
This also has the nice benefit of a 30 second failover. Simple change the server name in the settings file and restart the applications (web) and you have failed over (of course you have to restore your data if necessary).
Then when the application starts, we write the correct connection string to the web.config file (if it is different). With this, we can change a website from DEV to PROD by changing one appSettings value.
As long as there isn't too much, it's convenient to have it in the web.config. Of course, your DAL should have absolutely no clue that it comes from there.
A good option is for your data layer to be given its config information when it is called upon to do something, and it will be called upon to do something when a web call comes in. Go ahead and put the information in your web.config. In my current project, I have a static dictionary of connection strings in my data layer, which I fill out like so in a routine called from my global.asax:
CAPPData.ConnectionStrings(DatabaseName.Foo) =
ConfigurationManager.ConnectionStrings("FooConnStr").ConnectionString()
CAPPData.ConnectionStrings(DatabaseName.Bar) =
ConfigurationManager.ConnectionStrings("BarConnStr").ConnectionString()
etc.
"Injecting" it like this can be good for automated testing purposes, depending on how/if you test your DAL. For me, it's just because I didn't want to make a separate configuration file.
For testing purposes don't instantiate DataContext with default ctor. Pass connection string info to constructor.
I prefer to use IoC frameworks to inject connection to data context then inject context to other classes.
if you have a class library project that acts as ur DAL and it has an App.Config file with connectionstrings, how can I force it to use that config file? It keep getting values from the web.config in my Web Application project.
The DAL project uses LinqToSql. When I instansiate a DataContext object in my Web Application, from the referenced DAL Class Library project, can I make it use it's app.Config connectionstrings? It seems to ignore this file and tries to pick up connectionstrings from the web.Config connectionstrings node. There are no connectionstrings present there.
Any help is appreciated. A colleague mentioned making the app.Config in the DAL and embedded resource. Does that sounds like a good idea?
Thanks,
~ck in San Diego
Web applications always use web.config. Desktop applications always use app.config.
how can I force it to use that config file? It keep getting values from the web.config in my Web Application project.
You can't. If you use the System.Configuration classes, they will always pull from the active application's .config file (app.config for executables, web.config for asp.net websites).
Workarounds include using file i/o for reading your settings out (as opposed to the System.Configuration namespace) or putting your DAL configuration information in the appropriate .config file (the more common choice).
I'm not sure, but take a look at that:
using System.Configuration;
ExeConfigurationFileMap Map = new ExeConfigurationFileMap();
Map.ExeConfigFilename = FileName;
Configuration Conf = ConfigurationManager.OpenMappedExeConfiguration(Map, ConfigurationUserLevel.None);
AppSettingsSection section = (AppSettingsSection)Conf.GetSection("???");
Here's how I think of a *.config file. Say you have a method in your DAL:
DoSomething(connectString, SqlDialect, businessObject)
Since connectString and SqlDialect don't change with every call to this method, it would be nice to be able to remove those parameters and get those through some other means.
Well, *.config files are there for that reason--they are not only environment-specific, they are also app-specific. It's so your Web app can say, "Hey everybody, connectString = "..." and SqlDialect = "...", for every method call, until I say otherwise."
Let's say you want one app to log into SQL with one set of credentials, and another app to use another set of credentials (with different perms if necessary) so that the DBA can keep track of which app is doing what (if he/she so chooses). Well, *.config files make this happen.
That's why the app that you're running is the one that provides the *.config file. So just cut all the contents from your DAL's app.config file and paste it into your Web.config file, then delete App.config. You should be good-to-go after that.
I'm developing a web application (ASP.NET 3.5) that will consume a number of web services. I have created a separate dll-project for each web service: these projects contains the service reference and client code.
However, the calling website MUST have the <system.serviceModel> information (the <bindings> and <client> nodes) in it's web.config, even though this information is also in the dll's app.config file! I have tried copying the serviceclass.dll.config over to the bin directory of the website, but this didn't help.
Is there any way to centralize the configuration of a WCF client?
I've only limited WCF experience, all with BasicHTTP bindings. But I'm allergic to WCF's xml files and have managed to avoid them thus far. I don't recomend this generally but I put the configuration details in my apps existing configuration store and then apply them programatically. E.g. With a Web service proxy I use the constructor for the Client that takes 'bindings'and 'endpoint' and programatically apply the settings to the bindings & endpoint.
A more elegent solution appears to be descibed here: Reading WCF Configuration from a Custom Location, but I haven't tried it yet.
From my experience, library projects never read app.config.
So you can really delete the file because it is not used. The library's host configuration is read instead, so that is the only place the endpoint and binding configuration should be.
It's possible to forgo xml config and build up the Binding and Endpoint classes associated with the service in the constructor or a custom "Service Factory". iDesign has some good information on this:
http://www.idesign.net/idesign/DesktopDefault.aspx?tabindex=5&tabid=11
(See In Proc Factory)
In their approach, you set attributes on your services to specify at a high level how they should work (ie [Internet], [Intranet], [BusinessToBusiness]), and the service factory configures the service according to best practices for each scenario. Their book describes building this sort of service:
http://www.amazon.com/Programming-WCF-Services-Juval-Lowy/dp/0596526997
If you just want to share configuration XML config, maybe use the configSource attribute to specify a path for configuration: http://weblogs.asp.net/cibrax/archive/2007/07/24/configsource-attribute-on-system-servicemodel-section.aspx
Remember that a configuration file is is read by an executable that has an entry point. A library dll does not have an entry point so it is not the assembly that will read it. The executing assembly must have a configuration file to read.
If you would like to centralize your web configs then I would suggest you look into nesting them in IIS with virtual directories. This will allow you to use the configuration inheritance to centralize whatever you need.
There are 2 options.
Option 1. Working with channels.
If you are working with channels directly, .NET 4.0 and .NET 4.5 has the ConfigurationChannelFactory. The example on MSDN looks like this:
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = "Test.config";
Configuration newConfiguration = ConfigurationManager.OpenMappedExeConfiguration(
fileMap,
ConfigurationUserLevel.None);
ConfigurationChannelFactory<ICalculatorChannel> factory1 =
new ConfigurationChannelFactory<ICalculatorChannel>(
"endpoint1",
newConfiguration,
new EndpointAddress("http://localhost:8000/servicemodelsamples/service"));
ICalculatorChannel client1 = factory1.CreateChannel();
As pointed out by Langdon, you can use the endpoint address from the configuration file by simply passing in null, like this:
var factory1 = new ConfigurationChannelFactory<ICalculatorChannel>(
"endpoint1",
newConfiguration,
null);
ICalculatorChannel client1 = factory1.CreateChannel();
This is discussed in the MSDN documentation.
Option 2. Working with proxies.
If you're working with code-generated proxies, you can read the config file and load a ServiceModelSectionGroup. There is a bit more work involved than simply using the ConfigurationChannelFactory but at least you can continue using the generated proxy (that under the hood uses a ChannelFactory and manages the IChannelFactory for you.
Pablo Cibraro shows a nice example of this here: Getting WCF Bindings and Behaviors from any config source
First of all class libraries (DLLs) do not have their own configuration, however they can read the configuration of their host (Web/Executable etc.). That being said, I still maintain an app.config file on the library projects as a template and easy reference.
As far as the service configuration itself is concerned, WCF configuration can make somebody easily pull their hair out. It is an over-engineered over-complicated piece. The goal of your applications should be to depend least on the configuration, while maintaining flexibility of deployment scenarios your product is going to come across.
How can one specify the connection string in a config file of a class library and later modify this when used in a ASP.NET Web Application?
The Class library is a data access layer that has a Dataset connecting to a database based on a connection string specified in a config file (Settings.settings/app.config).
This class library is used in a web application where user inputs data and is written to the database using the DAL classes & methods exposed in the class library.
Now, I want to migrate this application from development environment to testing environment and later to production. The problem I'm facing is that after migrating to testing, the app in testing still connects to development database. I've changed the connection string mentioned in <class library>.dll.config file but this seems to have no impact.
Can someone explain the right way to achieve this? Thanks in advance for any help. Cheers.
With the .config files the name has to match the main executing assembly. For example I had a situation like yours, I needed a class library to have its settings in a .dll.config file. While it was able to reference it the actual application would not be able to read the config file because it was expecting .exe.config. Renaming the .dll.config to .exe.config fixed the problem.
In your case migrating your connection strings from .dll.config to web.config should fix your problem!
Good luck!
Joshua is partly right ... For posterity I would like to add a bit more to this answer as I have delt with the same problems on several occasions. First, one must consider their architecture. There are several issues you can run into with .config files in ASP.NET based on deployments.
Considering the architectural ramifications:
Single tier (one server):
A simple web application may be able to leverage a reference to the sites Web.config file and resolve your issues. This would be a fine solution for a single tier application. In the case of a windows application leveraged as a .exe file, the App.config will work too.
Multi-tier (more than one server):
Here is where things became a bit hairy for me the first time I was working with .config files across boundries. Remember the hierarchy of the config structure and keep this in mind (MSDN Article on .Config structure) - there is a machine.config at the root in the appropriate ASP.NET folder. These reside at each physical server. These are overridden by the site Web.config (or App.config) which are in turn overridden by subfolder .config files. If you have more than one .config file you may want to use one of the methods to pass the file path for the specific .config you want to use. More importantly, these files each may have connection information. ASP.NET's machine.config holds some for the framework ... so you should at least be senstive to the fact this is an "inheritance" chain. Second, any changes to the Web.config file once deployed will tell the application to restart. This will result in loss of state (bad if you have active users on the site). The way around this is to keep a separate .config file (e.g. connections.config) and put a reference to that file in the Web.config. This will allow you to change the connection information (e.g. password) without having to restart the application. Here is a link to more info: MSDN: Working with Configuration Files. This article lays out all the details you need to be aware of in a normal server / IIS deployed application. Keep in mind that the .config files are mainly intended for applications, not libraries. If you have several tiers, chances are you are using some communicaiton / messaging layer (e.g. WCF). This will have / allow its own Web.config. You can keep connection strings there (and encrypt them if needed), but better yet, put them in a second file referenced by the Web.config for manageability. One final point, if you are ever going to consider the cloud, .config files are wrapped for application deployments which in effect removes all of the benefits they offer in terms of "not having restart or redeploy". Azure deployments will want to consider this article to save themselves from nightmares of maintenance: Bill Lodin blog - Configuration files in Azul / Cloud. One other point on this article – great example on how to programmatically select configuration depending on deployment! Be sure to check that out if you want to add flexibility to deploy in or out of the cloud .
I hope these points saves all of you time and headaches. I know I lost a couple days of programming time dealing with these issues ... and it was hard to find all the reasons in one place why may app was not "implementing" its connection object. Hopefully this will save you all from the same fate I had.