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;
Related
I've got a C# solution of about 7 different projects, each with their own class to access our database. Right now I'm storing the database server, username, and password in the AppSettings of the app.config file for the startup project.
App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key ="dbServer" value="localhost"/>
<add key ="dbUser" value ="admin"/>
<add key ="dbPassword" value ="pw"/>
</appSettings>
...
</configuration>
In the same startup project, I have created a class to query for these values:
public static class DBConfiguration
{
public static String getDBServer
{
get { return ConfigurationManager.AppSettings["dbServer"]; }
}
public static String getDBUser
{
get { return ConfigurationManager.AppSettings["dbUser"]; }
}
public static String getDBPassword
{
get { return ConfigurationManager.AppSettings["dbPassword"]; }
}
}
Right now when I am in my Unit Test project, I am trying to call DBConfiguration.getDBServer, DBConfiguration.getDBUser, etc. and it is returning null. If I copy the same appSettings into the UT app.config, I get results. I'm a little confused how that is working. Since DBConfiguration is located in startup - shouldn't the calls to DBConfiguration refer to the app.config in startup as well?
Also, I have already added the reference to System.Configuration.
What you are seeing is by design. ConfigurationManager will pull settings from the current executing assembly. So if your unit test is the current executing assembly ConfigurationManager will get its settings from that app.config. This is useful for scenarios where you connect to different databases for testing purposes (which...you should be)
EDIT
ok so based on what you just mentioned about how you have things set up I feel compelled to ask why do you have it setup this way, and why do you have checks to see if you are in production or not. Sure there are valid reasons for it, but I think 99% of the time it can be avoided with a little forsight. However since your post was more about the app.config file I'll stick to that. When you have the same devs all needing to test some interaction with the database there are a few approaches one could take. One approach (and the one i'm most familiar with) is to use the repository pattern where you have a interface that returns or sets things according to a class. typical boiler plat code would be something similar to this:
public interface IRobotRepository()
{
IEnumerable<Robot> GetAllRobots();
Robot GetRobot(RobotParameters parameters);
void DeleteRobots();
void DeleteRobot(Robot robotToDelete);
}
granted a repository does not have to have both getters and setters, the point is that it is a way of stating your intent of what you want out of a repository (such as a database). It is simple and the point which is what I'm getting at though. With it you can easily mock it out and test functionality that depends specifically on that data. No specific configuration needed just all in memory things. Then for integration tests you can test that the repositories work as intended. Although you can have said repository on each dev's computer (such as using SqlLocalDb, or Sqlite's in memory database) those require a little more work with keeping it in sync with production. Just gotta balance the cost with that. Another option is to have a common QA/Dev/Sandbox database that is shared. There are tradeoff's with this approach too but normally isn't a big deal.
Keep in mind though that this is just one approach and there are tons of other approaches that people will scream to death is the best way. I just want to point out that there are multiple approaches to having multiple devs testing against a database. I'd be interested to see what your approach ends up being and showing why you went that path.
In my .net 4 solution, i have two different projects- an web application project and a class library project.
In web application project, database connection string is in web.config file. I would like to access that connection string from class library project. Is it possible? if yes, how?
If there is any better approach to get connection string, please let me know.
To access it from your class library add a reference to System.Configuration then use System.Confinguration.ConfigurationManager.ConnectionStrings.
It's not ideal to read this from a class library. After all, can you say that your class library will always be consumed by something with a configuration file? Certainly not if you share it with other developers, especially of different platforms.
Consider:
IoC - use dependency injection to provide a dependency that contains configuration settings. These would be populated by the consuming library (web app).
Pass the settings to the class library when consuming elements that depend on them.
e.g.:
public class MyLibraryContainer
{
private string _connectionString;
public MyLibraryContainer(string connectionString)
{
_connectionString = connectionString;
}
}
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).
Currently I have a static class that I use as my logging module. I’ve added the class to my visual studio solution. Within the class I’ve specified the name and location of the log file to use.
Which lets me do stuff like this – which I like and want.
Logger.Information(“Page_Load”,”controls loaded correctly”);
I’d like to refactor the code and move the logging functionality into a separately compiled assembly, if I did this I would then need to pass in the log file name and location to save the files too.
However I don’t want to have to supply this information every time I call the ‘Logging’ method, this would be bad...
Logger.Informtaion(“Page_Load”,”controls loaded correctly”,”logfile.txt”,”c:\temp”);
Is there any way I can supply this information without having to specify it within each page or via the method call.
For sure. The simplest thing would be to add a single key to the web.config file, which your class looks at by using the ConfigurationManager.
<configuration>
<appSettings>
<add key="logfile" value="c:\log.txt" />
</appSettings>
<system.web>
...
</system.web>
</configuration>
string logfile = ConfigurationManager.AppSettings["logfile"]
If your logging class is more complex than just one or two configuration options, consider building a ConfigurationSection class to go along with it, which would allow you to create your own section in the web.config.
The configuration approach is good for this type of thing, because then you avoid hard-coding the logfile path into your application code (such as passing it into a static initialization method), which would require a recompile if you needed to change the logging path. However, you should only need to look up the logfile path once, upon creation of your logging class.
I feel obliged to ask if you've investigated using TraceListener and the System.Diagnostics namespace with its built-in logging (as opposed to rolling your own). It's quite extensible.
Have you considered making your logger non-static? Perhaps a singleton? This is the classic example for an appropriate use of the Singleton pattern.
Sure,
Create an initialize method on your static class and pass the file into the initialize mentod. Then call the method at application start.
I am setting up a .net project that is called to generate other webpages. Basically a true CODE BEHIND page. How do I go about making a connection on a Class Library File, when there is no webconfig file present/available?
In this case, I would create a 'Base Page' that derives from System.Web.UI.Page. On this page, you would create a property called 'ConnectionString'. You will have all of your web pages you create inherit from this page.
Example:
public partial class BasePage : System.Web.UI.Page
{
protected string ConnectionString
{
get
{
return System.Configuration.ConfigurationSettings.AppSettings["MyConnectionString"];
}
}
}
And in your web.config
<appSettings>
<!-- Connection String -->
<add key="MyConnectionString" value="Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword;"/>
</appSettings>
Now you can have a web.config file with a connection string that is easily readable. And you can store this 'Base Page' in your class library, no problem. As long as your web pages inheriting from it are using the web.config file with the connection string.
After that, it's a simple matter of connecting using that string. You can do this in a variety of ways, either in your web pages, or in separate classes (I recommend separate classes). In this case, if you had a separate class, you would need to pass in the ConnectionString property to your connecting functions:
public void ExecuteQuery(string connectionString, string sql)
{
using (System.Data.SqlClient.SqlConnection theConnection = new System.Data.SqlClient.SqlConnection(connectionString))
using (System.Data.SqlClient.SqlCommand theCommand = new System.Data.SqlClient.SqlCommand(sql, theConnection))
{
theConnection.Open();
theCommand.CommandType = CommandType.Text;
theCommand.ExecuteNonQuery();
}
}
or you can create a function that does not take a connection string parameter, and just reads from the web.config file. It sounds like you may want to put your connecting and data access code in a class library for good separation of data and content. Hope this helps!
There are several ways to solve this:
1) If you're class library is really going to generate web pages, then it will probably be deployed on the server with the web.config and so can use properties of the web.config file. If you don't want to use the ConnectionString part, then you can just make an appSetting with the connection string.
The benefits of doing this are that it's easy to change or have different connection strings for different environments (testing, deployment, etc.). And if you decide to use the class library in another kind of app, you can use the app.config file with the same setting.
Depending on the type of database, you'll be using the System.Data and possibly some of the sub-namespaces to make this work.
2) You can hard code the connection string into the code. Ugly, but workable in a pinch.
3) You could use an entity framework to help you out and cut down on the work that you have to do.
System.Data namespace. If using SQL Server, a SQLConnection object.
I use the Application Data Blocks for data access b/c I think it is a time saver. That framework is great for SQL Server access.
Will your library be called from an ASP.net site? If so, you can still use the same methods for accessing the application settings. Otherwise, you may need some kind of app.config for whatever front end you're putting on this.
Also, you don't need a connecting in your configuration in most class libraries, unless you are using an ORM which needs to use it to pick up some info. The calling application's configuration will be used when you are running the thing, so it will pick up the configuration out of the web.config or whatever.