In a standard 3-layered application (Winforms Ui, BLL, DAL) i need to have settings specific for each layer.
Should i use the Winforms application settings to include all of them or i should have each dll (BLL,DAL) come with their settings?
I need a simple solution and not in a database or custom xmls, also i need to provide multiple UIs for the same architecture.
Update: Currently i am leaning towards separate .config files for each layer, i just dont know if this is the best practice that will allow for most of future changes (changes in layers and/or multiple UI apps).
Outcome: I think i am gonna have a static singleton class in every project that i need settings. I am gonna populate them by the upper layer every time with the most suitable way.
Custom xml file is flexible approach but need a bit effort.
Use a separate library project only to serve for settings, its easier way as you may use default settings class to save/load settings but not very flexible for nested settings.
Put all settings with DAL since it live at root and all other projects (UI, BAL) reference it)
Every time I tried to use the built-in app.config file, I ended up implementing my own config solution due to shortcomings of the built-in solution. Implementing a custom xml-based solution is not complex. It is actually very easy.
Just put this base class into your solution:
[Serializable]
public abstract class ConfigBase<DerivedT> where DerivedT : ConfigBase<DerivedT>
{
protected string FilePath;
public string FileVersion;
public ConfigBase() { }
public void Save()
{
XmlSerializer xs = new XmlSerializer(GetType());
using (StreamWriter writer = File.CreateText(FilePath))
{
xs.Serialize(writer, this);
}
}
public static DerivedT Load(string filename)
{
XmlSerializer xs = new XmlSerializer(typeof(DerivedT));
using (StreamReader reader = File.OpenText(filename))
{
DerivedT config = (DerivedT)xs.Deserialize(reader);
config.FilePath = filename;
return config;
}
}
}
Then you can make your configuration file like this:
public class Config : ConfigBase<Config>
{
// put your variables here like below
public string DatabaseConnectionString;
public int numberOfConnections;
}
Use it like this:
// Load it like this
Config config = Config.Load(ConfigFileName);
// Save it like this
config.Save();
Feel free to use properties, arrays and other complex structures within the config file. It will all serialize automatically. Use XmlIgnore attribute if you do not want certain fields/properties serialized. With this solution you can have many different configuration files, but have a single mechanism to load and save them.
I often include a public static Config GenerateDefault(string ConfigFileName) factory method inside the Config file, which will produce a sample config with default values.
Don't forget to check if the file file exists and load it within a try/catch block.
An even better solution would be to use DataContracts, which allows you to serialize private members and provides good mechanisms for supporting different versions of DataContracts, but it is a bit more complex.
If all your layers are running in the same AppDomain (rather than, say, hosting the BLL/DAL in a WCF service), then the KISS solution is to include all the configuration information in the client's app.config file.
You can use a naming convention to distinguish settings belonging to each layer.
UPDATE
From comment:
Currently yes, but I would like to be free to change later even the DAL presentation (via WCF for example).
That's simple: when you move a logical tier into a different physical tier such as WCF, you move its configuration into the configuration file for the host (e.g. web.config if the host is IIS).
Related
I am developing MVC application.
I have two projects in my application.
one is MVC application contains, Controller and Views and the second one is DataLayer project.
I am confused about the where to write the connection string, because while publishing the application it takes the web.config file and I get the data from DataLayer project so should I add connection string in the app.config/Web.config of Data layer project ?
Also, would like to know what is the purpose and difference between app.config and web.config ?
Every project comes with a configuration file when it's created. A general class library has a generic one called app.config. A web project is more specific, so its file is called web.config and comes with web-specific parameters. They both serve the same purpose.
The problem you are facing is that only the executable project's config file (web.config) is deployed by default. You have a few options:
Add your connection string to web.config and pass it to your data layer. This is simple (an most common), but separates the config info from your data layer project.
Have your data layer read web.config using System.Configuration.ConfigurationManager. This alleviates you from passing the data to your data layer, but creates a strong dependency (your data layer will not work without a properly formatted web.config file).
Deploy app.config as XML content and write custom code so that your data layer can read it. This is more work, but it gets your data config out of the web config.
A slight change to #2, you can create a custom config section called "dataLayer" in web.config. This can be read via System.Configuration.ConfigurationManager. I prefer this approach, as it seems like a good balance. You have a custom strongly-typed config section in the "default" config file.
This related question has some good info too.
The connection string goes in the Web.config. By default it's going to look in the config of the executing assembly and ignore the config files of the referenced assemblies.
The config file for the referenced assembly may be used at design time. For example if you are using Entity Framework in your data layer assembly, it will store the connection information that is used to build the model from the database in the app.config.
I generally just copy that connection information over to the web.config when I get to the point that the web project is going to run and access the data through the data layer.
Web.Config is used for asp.net web projects / web services.
App.Config is used for Windows Forms, Windows Services, Console
Apps and WPF applications.
Add your connection string in Web.config of Data layer project
I'll answer your question first, and then move on to what is, IMO a more important consideration. For this particular use case, I prefer a DI pattern, in which the consumer tells the provider what the connection string is. This makes your data layer agnostic of the database, and allows it to talk to any data store that satisfies it's contracts. In short, since your MVC project is the consumer of the data layer, the connection string is stored in the web.config. BUT IT IS STORED ENCRYPTED!!!
Now then, there is actually a deeper issue here than where you physically write the connection string, and that is building an abstraction between your consuming code and the configuration store. If you do this, where you store your configuration values becomes essentially irrelevant.
I always create a Configuration class within each layer (project) that provides the configuration values consumed within that layer. This provides several benefits:
It allows for strongly-typed values when consuming them. If your configuration value is an int, you get an int, and you don't need to convert it when you consume it.
It allows for defaulting values that may have been inadvertently left out of the config file. This makes your code more robust.
It allows for flexibility in where you store the values. You could put some values in a config file, others in a database, and still more could be fetched from a remote web service. If you decide to change a store, you only have to edit the code in one place -- not every place the value is consumed.
As your solution grows and projects are added, the pattern scales well and keeps configurations segregated.
It removes magic strings from your code.
Instead of the following, which has a nasty magic string:
return System.Configuration.ConfigurationManager.AppSettings["DefaultUserName"];
you would write
MyApp.Configuration.DefaultUserName
Here is an example of a very basic implementation which returns a strong type (in this case, a DayOfWeek). It has a helper method to help you abstract the act of pulling from the store. If you needed to include multiple stores, this method would take a generic of type T where T is the type of store. In the below, simplified example, it just pulls from the config file:
public class Configuration
{
private const DayOfWeek FailsafeDefaultDayOfWeek = DayOfWeek.Saturday;
/// <summary>
/// A default for the day of week
/// </summary>
public static DayOfWeek DefaultDayOfWeek
{
get
{
string dayOfWeekString = GetSettingValue("DefaultDayOfWeek");
try
{
return (DayOfWeek)Enum.Parse(typeof(DayOfWeek), dayOfWeekString);
}
catch (Exception)
{
// If someone screws up and forgets to include a value, or the value cannot be cast:
return FailsafeDefaultDayOfWeek;
}
}
}
/// <summary>
/// Helper method to easily pull a value from a configuration store.
/// </summary>
/// <param name="settingName"></param>
/// <returns></returns>
private static string GetSettingValue(string settingName)
{
try
{
return System.Configuration.ConfigurationManager.AppSettings[settingName];
}
catch (Exception)
{
throw new MissingConfigurationValueException(settingName);
}
}
}
I know EWL has support for services, but I'm not sure what is different about them or what steps I have to take to create one.
Also, is it possible to manually deploy an EWL service in the same manner as a conventional service, or do I have to use the deployment utility?
EWL services give you a simple programming model, with only three places you can put your logic: the Init, CleanUp, and Tick methods. Besides deciding how to divide your logic among these methods, no thinking is required. There is also no flexibility beyond these three methods, so if your problem doesn't neatly fit into this model, don't use an EWL service.
To create an EWL service inside an existing EWL solution:
Add a Windows Service project to your solution. Name it "Windows Service" or anything else. Set it to use the EWL NuGet package, just like the other projects in your solution.
In Library/Configuration/General.xml, add a section like this beneath <WebApplications>:
<WindowsServices>
<Service>
<Name>YOUR-SERVICE-PROJECT-NAME</Name>
<NamespaceAndAssemblyName>YOUR-SERVICE-PROJECT-NAMESPACE</NamespaceAndAssemblyName>
</Service>
</WindowsServices>
Update dependent logic.
Show hidden files in your service project, and add Generated Code/ISU.cs.
Add a Program.cs file to the project, containing this class:
internal partial class Program {
static partial void initGlobalLogic( ref SystemLogic globalLogic ) {
globalLogic = new GlobalLogic();
}
}
Add a CAMEL-CASED-SERVICE-PROJECT-NAME.cs file to the project, containing a class similar to:
internal partial class CAMEL-CASED-SERVICE-PROJECT-NAME {
string WindowsServiceBase.Description { get { return "..."; } }
void WindowsServiceBase.Init() {}
void WindowsServiceBase.CleanUp() {}
void WindowsServiceBase.Tick() {}
}
Remove any boilerplate files in your project that seem unnecessary.
I believe you can install EWL services manually. Just do a build and do whatever you need to with the files in the bin directory.
OK, so this is not the most useful question since I can't remember the feature in .net that does this. Basically, that's what I'm asking; what feature is this?
A year or so ago, I was working on a project and we used configuration files that mapped directly to a class using the specific attributes on the class members. This is not the standard app.config, but assemblyname.dll.xml instead.
Perhaps it's a feature within the unity framework? Just a stab in the dark.
It is not critical I figure this out today, but it is just weighing on my brain and annoys me that i can't remember!
thanks!
It's not the standard XML config, but it is built into .NET. Basically, XML serialization allows you to project an XML document from a hydrated class instance, that will map 1:1 to the class it came from and can be used to re-hydrate a new instance of that class.
This can, in the majority of cases, be done without much effort on your part. All that's usually necessary for XML serialization to work is that the object must have a public default constructor, and that all the state information you want to serialize must be public and read-write. In a few cases, some attributes are necessary to define certain behaviors, like derived classes in arrays of their parent class, and defining non-default names for field and property element tags.
One of the major uses of this is for custom configuration files as you stated; you can load the configuration from a persistent state by simply deserializing the file into an instance of the configuration object.
Article: MSDN How To Serialize an Object
This isn't part of the .Net bcl or Unity as far as I am aware. Perhaps it's some other third party or open source component? That being said, it wouldn't be too difficult to build something like this on your own using XmlSerialization.
.net allows for multi layered configuration.
Every machine has the machine.config file. each application has the app.config file (which gets renamed to applicationname.exe.config upon building), but each dll can also have it's own config file. so, if I have the following binaries in my executable folder:
flexitris.exe
flexitrisHelpers.dll
thirdPartyContent.dll
each of them can have their own config file:
flexitris.exe.config
flexitrisHelpers.dll.config
thirdPartyContent.dll.config
and all of them will be read at runtime and accessible using the normal System.Configuration namespace.
I'm looking for a good way to achieve the following:
I have a web application (MVC 3), with a separate Class Library that contains the back-end logic of a CMS that I'm making. This CMS uses NHibernate to connect to a database. I want the user to be able to configure the connectionstring (and eventually even the flavour of the database) in their web.config file.
What I'm looking for is a good way to get the connection string from the web.config file, even though the DLL is completely separate. Is this possible? Will I have to pass my connection string to my class library somehow? Or will I be able to access it when the application runs?
If I have to create some code in my web application to pass the connection string to my Class Library, how can I make this code as portable as possible, so I won't have to write it again for my next webapp?
Thanks a lot for any ideas you have.
You can pass in the connection string to the classes in the class library from the web site.
This is a better choice than trying to get the information directly from the configuration file, as otherwise you will have a dependency on the configuration file existing with the exact right key (making testing the class somewhat harder).
See this blog post for arguments against accessing configuration directly (which is very commonly done, but is not best practice).
You can access System.Configuration.ConfigurationManager from your class library. That'll give you access to the AppSettings and ConnectionStrings.
I have exactly the same setup with a FOSS project I'm involved with. It contains everything (even the Controllers and Global.asax.cs) in the 'Core' class library.
There's plenty of valid solutions, the one I opted for was to create a Settings class which is essentially a set of static properties, inside which you have:
public static string ConnectionString
{
get { return ConfigurationManager.ConnectionStrings["MYAPP"].ConnectionString; }
}
Note: make sure your class library has System.Configuration added as a reference.
Inside your Application (the class derived from HttpApplication) you pass the settings across, although there is nothing to stop you tighly coupling the NH setup with the settings class:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
SetupNHibernate();
}
public virtual void SetupNHibernate()
{
NHibernateRepository.Current.Configure(RoadkillSettings.DatabaseType, Settings.ConnectionString, false, Settings.CachedEnabled);
}
If this is any use to you, the source is here.
You can use the ConfigurationManager class to access items in your web.config or app.config file. However, in your class library, be sure to take in the key name of any appSettings and/or connectionString settings from the consumer (preferably in the constructor). This avoids the problem of you choosing a key name that the consumer is already using elsewhere.
Since you are using the class library to the MVC web application, it is accessible to the class library also. No additional settings are needed. Even though the class library when built giving a separate dll, it is referenced in the current project. So the connection string will be available to the class library also.
I'd go with something like Autofac to give you some IoC implementation which can store a settings interface for your connection strings. This would allow you to setup the value from the web.config on application start, or to set it within tests to a different value without your Class Library ever having to be coupled to a web.config.
You can add new Existing item from another project to your class library. Then change Build Action to Embedded Resource and Copy to Output Directory to Copy if newer on the Web.config file.
Web.config in another project
<configuration>
<appSettings>
<add key="MyConfigValue" value="Test" />
</appSettings>
</configuration>
Class library test file
var doc = XDocument.Load(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Web.config"));
var myConfigValue = doc.Element("configuration")
.Element("appSettings")
.Elements("add")
.FirstOrDefault(e => e.Attribute("key").Value == "MyConfigValue").Attribute("value").Value;
I'm playing around with .NET's configuration support (the ConfigurationManager class and related support classes). I would like to write an application that, once installed:
Has default settings in foo.exe.config (in Program Files).
The user may later override the settings with nondefault values which should be persisted.
The user's preferences should be persisted in the user's profile, since he shouldn't have write permissions to the Program Files directory.
The app should use the user's preferences when they're set, otherwise use the defaults.
It seems like this ought to be easy - it's a very common pattern. But my attempts at this are running into bumps and I'm wondering if I'm taking the right approach.
The following code produces the runtime exception "ConfigurationSection properties cannot be edited when locked".
using System;
using System.Configuration;
namespace DemoAppSettingsProblem
{
class Program
{
static void Main(string[] args)
{
Configuration userConfig =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
if ( userConfig.AppSettings.Settings["foo"] != null )
userConfig.AppSettings.Settings.Remove("foo");
userConfig.AppSettings.Settings.Add("foo", "The string is foo.");
userConfig.Save(ConfigurationSaveMode.Modified); // exception!
}
}
}
The problem is that the .NET-defined <appSettings> section is declared with the default allowExeDefinition=MachineToApplication (see this nice post by Microsoft's Irena Kennedy). This prohibits the section from being written to the user's profile (either local or roaming).
So, I assume I need to define my own section, with allowExeDefinition=MachineToLocalUser. But as far as I can tell from the MSDN docs, that means I need to create my own configuration class, derived from ConfigurationSection. The examples there point me toward more work than I was expecting, which usually sets off my alarm bells that I'm doing something wrong.
Is it really this difficult to achieve this? Is there a simple way .NET provides to support this, or should I perhaps be taking a different approach altogether?
I've used the settings feature, it writes user settings to the app config for you...
http://msdn.microsoft.com/en-us/library/aa730869(VS.80).aspx
Assuming you're on .NET 2.0 and higher, have you checked out the "Settings" files? Those are being stored inside your app.config - application settings in <applicationSettings> sections, user-definable settings in <userSettings>, which incidentally have the allowExeDefinition=MachineToLocalUser setting you mentioned.
Maybe that could be an approach? Those user settings are a defined type, which you could definitely reuse under a different name, if needed ("mySettings").
Marc