I have a C# project that outputs a dll: foo.dll. This foo.dll internally uses a legacy library legacy.dll. Here is how my library foo.dll will be used: first I upload these files: foo.dll, legacy.dll, and legacy.dll.config to a third party; then the third party starts up a process which loads my main library foo.dll and executes some functions. When foo.dll is being run, I see exception thrown in legacy.dll saying some configuration "baz" cannot be found. However, I can verify that the configuration "baz" is defined in the legacy.dll.config file. So I think the file legacy.dll.config is not loaded by the process.
So I wonder how config.dll files are used. In my case, considering foo.dll is the only thing within my control, is there a way to load the legacy.dll.config file?
One solution is to place the configuration section that your legacy.dll requires in the configuration (app.config or web.config) for the application that references it.
Do you have control over your legacy application - in other words, are you able to modify it? One occasional challenge is that when all of these extra values are dumped into the configuration it can be more difficult to tell where they are used. They can even get left in the configuration long after you stop using legacy.dll because no one knows what they are and they're afraid to remove them.
Going the other way, if the values are missing from the configuration, it's best not to throw a confusing NullReferenceException or configuration exception that requires someone to dig into the legacy code and figure out why it doesn't work.
There are a few things you can do to make this easier:
One is that your legacy.dll can look for configuration values that are distinct and separate from the rest of your configuration.
That could mean a separate configuration section like
<section name="stuffTheLegacyDllNeeds" type="Legacy.LegacySettingsConfiguration, Legacy" />
<stuffTheLegacyDllNeeds>
....
</stuffTheLegacyDllNeeds>
Or you can disambiguate the appSettings keys with some convention like
<add key="myLegacyLibrary:someSetting" value="true" />
You can also make it easier for other developers by throwing useful exception messages if a required key is missing, like "Legacy requires appSettings key 'xyz' which was not found." They still have to figure out where to find the values but at least they have a clear understanding of the problem.
Also, if you find that Legacy.dll doesn't change settings often or ever, you can code it to replace missing values with default values. That way they can override the defaults if they need to by adding configuration values. But if they don't need the defaults they can just not supply configuration values.
One more approach - this is the one I personally prefer:
Make your legacy class depend on an interface for settings like
public interface ISettings
{
bool SomeSetting { get; }
int SomeOtherSetting { get; }
}
and make your legacy class require an instance of ISettings in its constructor. Now the app that references it "knows" about the settings because it can't use the class without providing it. Your legacy library can provide an implementation like
public class ConfigurationSettings : ISettings
that reads from configuration, and the referencing app could choose to use it. Or it could supply another class that implements the interface. It could also provide a class that contains default values which the referencing app could change. It could also have a set of defaults that it uses internally if the referencing app doesn't provide any values.
Now,
The referencing application knows that your class needs these settings.
The referencing application can choose how to provide them.
Your legacy library no longer depends on the configuration. It depends on an abstraction - ISettings - which can be implemented using configuration or some other way. That means your legacy library will be easier to unit test. Code that explicitly depends on configuration values is much harder to test, or likely never even gets tested.
Related
The storage admins where I work have bought and configured a new huge NAS system.
Over time all current storage will migrate over there. This means that various network paths will change and this will break some in-house applications. We are reviewing a bunch of old apps the find the ones that use current paths like: \\old-file-system.company.com\Users so that we can modify them.
The old apps I have found all set these paths as strings in the project web.config file. My question is: are these paths compiled into the executable or are they read at runtime from this config file? Can we just modify the paths in the config files and not have to potentially rebuild them or upgrade them to newer .Net versions?
Cheers
The values are read from the config file.
That is precisely the point of config files: to provide the ability to alter these values without needing to redeploy the application.
Note that this may need you to restart the app pool on IIS after making changes. Usually, it should automatically do that when it detects changes to the config file, but from historical experience this sometimes breaks without you noticing.
As an aside: don't forget about alternative config storage methods such as databases.
yes, they are!
it will then depend on the code.
So, As a general rule no.
However, if you added new config items, then they may well not show up.
And if the code used the built in class in place of often used configuration manager to get values?
then you have to re-compile.
But, we also might use this:
vb.net:
Dim rstData As New DataTable
Using cmdSQL As New SqlCommand(strSQL, New SqlConnection(My.Settings.TEST3))
cmdSQL.Connection.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
So, in place of config manager, I often use My.Settings.TEST3.
(you get intel-sense). So on build, a class is created for some of those web config files.)
In c#, the above is:
Properties.Settings.Default.TEST3
And again often used due to intel-sense in place of configuration manager.
That class is re-build at compile time. So, if the code used to get web.config values is always configuration manager, then you would/should be ok.
However, if code used the built-in class like above?
The values ARE pulled from web.config at compile (build) time.
the class is called
c#
Settings.Desinger.Cs
vb.net
Settings.Desinger.vb
So, I would check the above two files. That class tends to come from here:
Now the above when we add say a connection string to the project?
The above DOES update and put the above settings into web.config.
However, the class created (settings.Desing.cs/vb?
It is re-generated each time, and it DOES COPY the values from web.config.
So this means that after changing the settings in that project, you REALLY do have to re-build.
As noted, if one came from desktop land, then we just add settings to above, and use them. They actually are created in web config, but we often use the above - since as noted ANY new setting we add to the project now has intel-sense.
So, I would search the source code for:
vb:
My.Settings.TEST3
(search for My.Settings.)
or
c#
Properties.Settings.Default.TEST3
(search for Properties.Settings.)
if either of above are used in the code?
Then yes, you have to re-build since they are re-created at compile time into a class, and the values ARE pulled from web.config at compile time.
If configuration manager was used in all cases, then you are ok.
however, if the designer class was used, then a re-build is required, and worse a change in web.config will not be reflected in that class until a re-build.
I'm writing a set of plugins for a third-party application which are implemented as .NET libraries and are loaded on application start, so they are all in the same application domain. One of the libraries is a collection of utility classes and extension methods that are used by others (including plugins written by other people, so this is basically a meta-library).
The problem is: inside the utility library there is an initialization code that allows to set up things like plugin title and such; which are, obviously, should be set per-client, i.e. per library in that case. This, of course, cannot be achieved using a static configuration class, as there would only be the single instance of it within the domain.
I'm also not allowed to load this library dynamically inside other plugins into a separate domain; and that will be a waste of memory, which is a concern.
The questions are:
Is it even possible/reasonable to implement such per-client runtime configuration for other libraries?
If it is, what approach would you recommend?
I am not sure I understand the question correctly, but you seem to be suggesting that there is an app which loads plugin-dlls at startup. You (the app developer and potentially plugin developer) want to provide a static class which has utility functions, that the plugins can use, without having to "re-invent the wheel" for every plugin. Below is my assessment (based on the above understanding)
Your utility class seems to store plugin specific data - so by definition it cannot be static
Yes, you can potentially load a plugin specific configuration file (file name might have to follow a naming convention to be effortlessly loaded by a static function) and offer the utility services - but I would say that is a bad design
I would rather provide a utility which does not store any plugin specific data, but simply provides services based on method arguments. If you see yourself passing the same parameters a lot of times to the utility, then you should encapsulate those parameters into its own class/struct (like PluginData?)
EDIT
Let me expand a bit on the 3rd approach specified above:
You can represent your plugin configuration using a class, something like below, or you can get fancier.
class PluginConfiguration {
public string PluginName {get; private set;} // This represents a property that all plugins share i.e. well known properties
// all the configurations "private" to the plugin can go here
// You might want to use some XmlDocument or a different data structure for this purpose
public Dictionary<string,string> ConfigItems {get; private set;}
public PluginConfiguration(string configFile) {
// Load the configuration from the config file
}
}
Now your utility library can pass arguments or return data of type PluginConfiguration and help you centralize all repeating code for plugins
I'm developing a Class Library / API and I need to store some global parameters that will be used by some classes. I thought about two main ways to do so (ignoring configuration files which I'd prefer not using in this case):
1) Specifying the parameters in a static class, like this:
// Stores and validates settings
ApiConfiguration.SetConfiguration("some values or class here");
var methods1 = new MyFirstApiMethods();
methods1.DoStuff(); // Internally uses static ApiConfiguration.
var methods2 = new MySecondApiMethods();
methods2.DoOtherStuff(); // Internally uses static ApiConfiguration.
2) Creating an instance of the configuration class and pass it to the classes, like this:
// Create an instance of the configuration class
var config = new ApiConfiguration();
config.ServerName = "some-server-name";
var methods1 = new MyFirstApiMethods(config);
methods1.DoStuff(); // Uses the supplied ApiConfiguration instance.
var methods2 = new MySecondApiMethods(config);
methods2.DoOtherStuff(); // Uses the supplied ApiConfiguration instance.
The fist option feels more natural for me, but I can think of some possible downsides (if the config is set in two places with different values, for example).
I want to know the possible downsides of each implementation and what is the most common way to do this in known projects of this nature.
I'd say #1 is the most common. I know you said that you didn't want to use configuration files, but if you look at how .NET uses app.config I think you will see that a similar approach to #1 is taken. You don't see instances of app.config settings being passed around to every method/function that needs to read a setting. I normally do VB.NET, for which there is a static My.Settings class that basically achieves the same thing as your #1.
The biggest disadvantage I see to #2 (and probably why it is less common) is that the config class can get passed around a lot. If only a small number of methods actually need to read the config it might be ok, but if many methods need to read the config it starts to become a headache. In my opinion it also clutters up the method signatures. Imagine a class deep in the library that needs to read the config; you may have to pass the config through several higher level classes just to pass it through to the class that needs it.
I'd recommend at least considering using app.config or web.config as either one of these already have built in functionality for this type of thing.
EDIT
I was waiting for Brannon to respond with an example, but since he hasn't I'll go ahead and chime in. IOC containers are great tools to help with dependency injection, but I wouldn't dream of introducing one just for a settings class. If you were already using one, that might be a different story. Lets suppose that you were already using an IOC container and wanted to use it for your config class. That means you still have method signatures that look like:
Function Add (FirstNumber, SecondNumber, Config)
Admittedly that example is a stretch, but you get the idea. The IOC container will resolve your Config dependency (it will create the config class for you), but you still have the config as a parameter to each method/constructor that needs it.
To be honest some of it comes down to personal preference. Keep in mind that VS/.NET uses #1 out of the box when you use app.config. I know that static classes are frequently frowned upon and rightfully so in many cases, but I think that settings/config classes are exceptions to the rule.
We are having problems accessing information in .net configuration files (such as app.config and web.config) via unit tests when the unit tests have a host type of "Moles". It's causing quite a few headaches, so I hope someone has an idea on what can be done.
We're using Visual Studio 2010, and I believe we've tried this on a machine with VS 2010 SP1 installed, and machine without SP1 installed, as well as trying it on 32 bit and 64 bit machines.
I've taken the liberty of reducing the test to its simplest terms. The problem can be recreated by composing a unit testing project consisting of the following two files, and running the test after uncommenting the only commented line. The test works without a host type, but when you introduce Moles as a host type, the null assertion in the test fails. We are not sure why.
First, the configuration file App.config:
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="Connection" connectionString="Something" />
</connectionStrings>
</configuration>
Next, the test class containing a single test:
namespace TestProject
{
using System.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class UnitTest
{
[TestMethod]
//[HostType("Moles")]
public void TestMethod()
{
var data = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
Assert.IsNotNull(data.ConnectionStrings.ConnectionStrings["Connection"]);
}
}
}
I would be grateful if anyone could offer any insight.
Thanks very much,
Nick
I'm not sure if it will do the job, but you can try this workaround: open the config using a file mapping.
The code will look like this:
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = configurationFilePath;
System.Configuration.Configuration configuration =
ConfigurationManager.OpenMappedExeConfiguration(
fileMap,
ConfigurationUserLevel.None);
Any time you are performing unit tests, application and user settings should be passed via dependency injection. This is accomplished by creating a Stub for the settings, which is easy to do.
Create an interface, in the project being tested, that includes a property for every configuration setting. Lets call this "ISettings," for reference.
Create a stub (class) in the target assembly that implements the interface. Each property in the stub should contain only a get that returns the corresponding setting form the configuration file. We'll refer to this stub as "SettingsStub". This stub is used by the target assembly, in the production environment.
Add an ISettings typed argument to the target type (class being tested) constructor. A field in the target class must be set to the ISettings object passed to the constructor. You may create an overload constructor, and preserve the default constructor, as required by some design patterns (MVVM, etc.). The default constructor (the one that has no arguments) may simply instantiate a new SettingsStub, for use in production. The overloaded constructor must always be used by tests!
Create a settings stub to the test project, that also implements ISettings. We'll refer to this as TestSettingsStub. This stub contains hard-coded values that are acceptable for most tests.
Rebuild the target and test projects. Moles generates a Stub type named SISettings.
Use the concrete TestSrtyingsStub, when you don't need to adjust any of the setting values. Alternatively, use the Miles Stub type, when the values need to be adjusted for one or two tests. The purpose of the Moles Stub types is to avoid the need to make many stubs that contain one or two unique changes.
The SettingsStub, TestSettigsStub, and SISettings types may be used interchangeably, when calling the overloaded constructor. Now, you have full control over what settings are used in each context, without the need for switching logic or manually changing setting values, during testing. The target code simply retrieves setting values from the local field, instead of directly from the configuration file. Please refer to Dependency Injection and Inversion of Control (IOC) topics.
As usual, your development workstation development not be able to access external dependency systems (database, etc.) on the production network, for safety!
Happy coding!
I'd agree that Mike's answer is logically correct (i.e. you're not separating your configuration loading from the class - potentially), the practical matter is that for Moles host types, per your original question, you'd need to Mole the calls to the configuration system, e.g.
MConfigurationManager.AllInstances.OpenExeConfiguration (... finish your moleing here...)
The syntax is approximate - I can't remember if you end up with an SConfigurationManager or MConfigurationManager in that case.
Where I wholly disagree with Mike is that the statement "...development workstation not be able to access external dependency systems..." is flat out horrible advice. We make these things called integration tests.
Yes, you as a developer should be creating them. At some point you will write code that touches a concrete implementation (e.g. a database, backing service, etc...) and if you're not testing that interaction, you're pretty much doing it wrong.
If I go to Project -> Myproject Properties -> Settings I can create a settings file for the entire project. However supposed each class requires its own configuration file. Is there a similar way to do this at the class level?
By way of example suppose I have a parent class Car with subclasses Ford and Honda. I want to have a single property YEAR and a single piece of code for reading the YEAR property. I could do this by having two configuration files with the same YEAR property. If I used Ford.YEAR and Honda.YEAR than I would need two separate pieces of code for parsing the data which could get messy for a large number of classes.
It's not really designed for that.
You can use the System.Configuration.ConfigurationSettings classes to open a file explicitly in code to read your settings from. THis will work however the designer will give you no assistance creating your settings files.
Do you have an issue with class wide settings?
Another way that might help you is to create a custom configuration section which you can put in the file. Then you can split each of your classes settings into it's own configuration section. That might suit your purposes?
Configuration data is stored for an executable in its config file (which is a single file, regardless of the number of "settings" files in your project) and is not class-specific. You can set naming conventions for your setting keys configuration options related to a class like ClassName.ConfigName.
You could to create specific sections for your subclasses: How to: Create Custom Configuration Sections Using ConfigurationSection
When you start a .net application, it takes your entry point assembly configuration file and load it up into memory. But just one.
So, if you have a MyApplication.exe which uses a MyLibrary.dll and both have configuration files, just MyApplication.exe.config will be loaded.
You'd have to do it manually, as the others have suggested. However, I'd strongly recommend against this, as I would think you'd have a configuration nightmare to deal with in the end.
As per the other answers, no configuration files are not class specific, you'd be best off creating a class which handles retrieving and setting configuration (a ConfigManager-style interface).
I'd have to ask you though, do you really want configuration per class?
That sounds like a configuration management nightmare scenario. You'd have to entertain scenarios where configuration is either missing or invalid on a per-class basis - and take appropriate steps accordingly.
If your design calls for per-class configuration, perhaps you would be better served storing it in a database or using another medium?
Many of the current IoC containers would allow you to do such a thing through its dependency injection (DI) possibilities. In fact, when XML configuration was all the rage in DI land, you would pretty much get all this out of the box. Today many IoC containers support a programmatic way of setting up dependencies, which you can quite easily hook to whatever XML file you want to provide. Check out this example with the IoC container StructureMap:
IContainer c = new Container();
c.Configure(ce=>
ce.For(typeof(A)).Use(typeof(A)).WithProperty("Test").EqualTo("Hello"));
var a = c.GetInstance<A>();
Debug.Assert(a.Test == "Hello");
By parsing an XML file containing information like targeted type, name of the property, its value, and then calling the above API, you can get what you want.