Well, I'm making my foray into this fantastic site with a question about the correct way to inject configuration settings into application components. So, the overview is : I have an application written in C# .Net 3.5. It consists of 3 assemblies - a Core, a Data and a Service. The data & service assemblies require settings retrieved from the app.config, which is done via a settings file, eg.
Code :
public static String RequestQueueConnectionString
{
get { return ConnectionSettings.Default.RequestQueueConnectionString; }
}
Config :
<applicationSettings>
<MyNamespace.Data.ConnectionSettings>
<setting name="RequestQueueConnectionString" serializeAs="String">
...
Now, the assemblies are all setup using StructureMap for IoC - which to my mind should provide the answer to what I am looking for, but I just can't quite see it!
IoC :
public static void ConfigureStructureMap(IContainer container)
{
container.Configure(x => ...
...
What I want to be able to do is to inject a configuration class already populated into the IoC container such that those settings are used for that assembly, NOT those specified in the settings file / app.config. So perhaps :
public static void ConfigureStructureMap(IContainer container, MyConfigClass config)
{
container.Configure(x => x.For<DataConfig>()
.Singleton()
.Use ???
...
I hope I have provided enough details here - forgive a newbie if I have not and please let me know what else would be helpful in answering this!
So, after a lot of searching and trial and error, I was presented with #default.kramer's link, which I duely followed! With a little bit of trial and error, again (best way in my opinion), I managed to get the solution I was looking for. Now, whilst you can follow the link (and I would highly suggest doing so), I am going to post the solution to my question as I implemented it. Hopefully this might help someone with a similar problem.
So, I now have my configuration setup class like so :
public static class DispatchConfiguration
{
public static void ConfigureStructureMap(IContainer container, IDispatchConfiguration dispatchConfig)
{
DispatchProcessBatchSize = dispatchConfig.DispatchProcessBatchSize;
ServiceIsActive = dispatchConfig.ServiceIsActive;
...
}
Now, before I was using a settings file to retrieve the configuration out of the app.config file. This was obviously good for ensuring I had flexibility in changing my config settings, but it left me with the problem of not being able to easily test those settings. Say 9/10 tests required the service to be active, but 1 test wanted to test "ServiceIsActive = false;", now I'm in trouble.
Now, however, I am able to inject the configuration from the test :
[Given(#"Config\.IsServiceActive returns false")]
public void GivenConfig_IsServiceActiveReturnsFalse()
{
var settings = new DispatchSettings
{
ServiceIsActive = false,
DispatchProcessBatchSize = 100,
UpdatedBy = "Unit Test"
};
DispatchConfiguration.ConfigureStructureMap(ObjectFactory.Container, settings);
}
And then in the real world I am able to get the settings from app.config :
public void Start(String[] args)
{
var dispatchConfig = this.GetDispatchConfiguration();
DispatchConfiguration.ConfigureStructureMap(ObjectFactory.Container, dispatchConfig);
...
}
private IDispatchConfiguration GetDispatchConfiguration()
{
var config = (DispatchSettings)ConfigurationManager.GetSection("DispatchSettings");
return config;
}
And then the actual config class looks like :
[XmlRoot(ElementName = "DispatchSettings", Namespace = "")]
public sealed class DispatchSettings : IDispatchConfiguration
{
public Int32 DispatchProcessBatchSize { get; set; }
public Boolean ServiceIsActive { get; set; }
...
}
For the sake of completeness the interface looks like so :
public interface IDispatchConfiguration
{
Int32 DispatchProcessBatchSize { get; }
Boolean ServiceIsActive { get; }
...
}
And finally, the config file looks like this :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="DispatchSettings" type="MyNamespace.XmlConfigurator, MyNamespace.Core" />
</configSections>
<DispatchSettings type="MyNamespace.DispatchSettings, MyNamespace.Core">
<ServiceIsActive>True</ServiceIsActive>
<DispatchProcessBatchSize>100</DispatchProcessBatchSize>
</DispatchSettings>
Now, anyone with a keen eye will spot "MyNamespace.XmlConfigurator". I found this on one of my Google journeys, and the code allows you to deserialize an Xml config into a class of your desire (as shown in this example). So, to ensure you have the complete code to make this technique work, below is the code for the XmlConfigurator. I cannot remember where I came across it, but a big thanks to the person who wrote it!!
public sealed class XmlConfigurator : IConfigurationSectionHandler
{
public XmlConfigurator()
{
}
public object Create(object parent, object configContext, XmlNode section)
{
XPathNavigator navigator = null;
String typeName = null;
Type sectionType = null;
XmlSerializer xs = null;
XmlNodeReader reader = null;
try
{
Object settings = null;
if (section == null)
{
return settings;
}
navigator = section.CreateNavigator();
typeName = (string)navigator.Evaluate("string(#type)");
sectionType = Type.GetType(typeName);
xs = new XmlSerializer(sectionType);
reader = new XmlNodeReader(section);
settings = xs.Deserialize(reader);
return settings;
}
finally
{
xs = null;
}
}
}
And there you have it! I hope this allows anyone with a similiar issue to resolve it and is clear enough to follow!
Related
I'm just taking my first baby steps in the MEF territory and wanted to do so using .net core 2.1.
Using VS 2017 (version 15.8.8) I've done a small Console App (.NET Core) with an interface
interface IMessageSender
{
void Send(string message);
}
and an implementation (in the same project)
[Export(typeof(IMessageSender))]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine("EmailSender : " + message);
}
}
Finally I have a small compose method executed from my Main(string[] args)
[Import]
private void Compose()
{
var assembly_A = new[] { typeof(Program).GetTypeInfo().Assembly };
var config_A = new ContainerConfiguration().WithAssembly(assembly_A[0]);
var container_A = config_A.CreateContainer();
var msg_A = container_A.GetExport<IMessageSender>();
msg_A.Send("Hello");
}
It works as expected
However, if I add a new class library to my solution and move my implementation of Send(string) to the newly added project things do not work out.
namespace AnotherMefExtensionProjectNamespace
{
[Export(typeof(IMessageSender))]
public class EmailSenderExtended : IMessageSender
{
public void Send(string message)
{
Console.WriteLine("EmailSenderExtended : " + message);
}
}
}
The new Compose method
[Import]
public IMessageSender MessageSender { get; set; }
private void Compose()
{
var assembly_B = new[] { typeof(EmailSenderExtended).GetTypeInfo().Assembly };
var config_B = new ContainerConfiguration().WithAssembly(assembly_B[0]);
var container_B = config_B.CreateContainer();
var msg_B = container_B.GetExport<IMessageSender>();
msg_B.Send("Hello");
}
I've tried to compare the different configs and containers (_A versus _B in the examples) but can't understand what is different. I've even tried to extend the class ContainerConfiguration to load from a specified assembly and it works as long as the given file contains the Main method but fails if I use my "extended" .NET Core Class Library.
public static ContainerConfiguration WithChosenAssembly(this ContainerConfiguration configuration, string pathAndFile)
{
var context = AssemblyLoadContext.Default.LoadFromAssemblyPath(pathAndFile);
var ass_list = new List<Assembly>() { context };
configuration = configuration.WithAssemblies(ass_list, null);
return configuration;
}
I was under the impression that you extend your main application by developing a class library that basically implements the interfaces specified.
I seem to be unable to do this currently, but obviously I misunderstood something very basic.
If someone would care to put me on the right track or give me an alternative idea for "plug-in" development for .net core I would be very grateful.
King regards
Magnus
I realized that my test setup does not mimic any real world scenario and thus I brought my problems on myself.
Obviously I should have had three projects.
One project with only the interface definitions.
One "main" project where all my regular code exists.
One (or more) projects where my MEF implementations of the interfaces exist.
Reviewing my example and adhering to the obvious "design" above it all works exactly as it should.
Most StackOverflow users probably wouldn't make my blunder but for those that did, I hope the above helps. :-)
I have a scenario where I have a set of credentials for each environment
e.g. for dev env username1/pwd1, for qa env username2/pwd2, for staging username3/pwd3 and so on.
Now I want to create a class which will return me a set of credentials based on the env I feed to it.
All the data has to go within code (as per my brilliant boss, no xml files and all), what design pattern I could use so that the code will be elegant and data can be made extensible in future?
Personally, I am used to create a channel attribute:
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public sealed class AssemblyChannelAttribute : Attribute
{
public ChannelType Type { get; private set; }
public AssemblyChannelAttribute(ChannelType type)
{
this.Type = type;
}
}
public enum ChannelType
{
Dev,
Beta,
PreProd,
Prod
}
This attribute is set on the Assembly:
#if DEBUG
// In release mode, this attribute is set by the MSBuild script
[assembly: AssemblyChannel(ChannelType.Dev)]
#else
As the comment said, the value of the attribute is set on compile time by my MSBuild script (too tied to my project to show you this part).
Once you have setup all of this, you can create a simple singleton like this:
public class Credentials
{
private static readonly Lazy<Credentials> instanceHolder =
new Lazy<Credentials>(() => new Credentials());
public IReadOnlyDictionary<string, string> Passwords { get; private set; }
public Credentials Instance { get { return instanceHolder.Value; } }
private Credentials()
{
var channel = typeof(Credentials).Assembly
.GetCustomAttributes<AssemblyChannelAttribute>()
.ElementAt(0)
.Type;
switch (channel)
{
case ChannelType.Dev:
this.Passwords = new ReadOnlyDictionary<string, string>(new Dictionary<string, string>
{
["User1"] = "Pwd1",
["User2"] = "Pwd2",
// etc
});
break;
case ChannelType.Beta:
// etc
break;
case ChannelType.PreProd:
// etc
break;
case ChannelType.Prod:
// etc
break;
}
}
}
Then you can access your credentials like this:
var password = Credentials.Instance.Passwords["User1"];
If you use .Net core, you could use the configuration techniques.
They are very powerful and work in asp .net as well as console programs
They are very configurable and composable (pass in config via cmd and json for example)
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration
What you're after is the Multiton design pattern.
i am using the NLog built in support for castle and trying to find a way to alter the connection string at run time.
this is my latest swing and miss, im sure it has to do the life cycle at this point as all of the configuration is null so i am guessing that castle has not yet wired up the guts on NLog.
private const string NLogConnectionString = "NLogConnection";
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<LoggingFacility>(l => l.UseNLog());
var config = new NLog.Config.LoggingConfiguration();
var dbtarget = config.FindTargetByName("database") as DatabaseTarget;
if (dbtarget != null)
{
dbtarget.ConnectionString = MethodThatGiveMeConnectionString(NLogConnectionString);
}
}
looking at this post it could be an option but based on the way things have been done here i dont want to change that and much prefer just providing the connection string directly to NLog.
looking here I know i can configure this at run time but i much prefer let most of the settings come from the config file and then just override the connection string.
So I found a solution that works but not sure it's the best approach.
Using this post as a reference. This comment was the most helpful:
Initially I tried to implement a custom ILoggerFactory and inject it into LoggingFacility via the customLoggerFactory. But that soon proved to be a dead end. Then I looked into the NLog integration and noticed that there's already a NLogFactory that has it's methods marked as virtual. So I was able to derive from this class
The problem the author is solving is different than my own but it got me to come up with this solution:
public class LoggerInstall : IWindsorInstaller
{
private const string NLogConnectionString = "NLogConnection";
public void Install(IWindsorContainer container, IConfigurationStore store)
{
var config = new NLog.Config.LoggingConfiguration();
container.AddFacility<LoggingFacility>(l => l.LogUsing(new OwnNLogFactory(GetYourConnectionStringMethod(NLogConnectionString))));
}
}
public class OwnNLogFactory : NLogFactory
{
public OwnNLogFactory(string connectionString)
{
foreach (var dbTarget in LogManager.Configuration.AllTargets.OfType<DatabaseTarget>().Select(aTarget => aTarget))
{
dbTarget.ConnectionString = connectionString;
}
}
}
Still not sure this is the best solution but it works for now, would love to see other solutions if anyone has one
I want to have a component register other components in the registry as / after it's constructed. Let's say I have the following components:
interface IConfiguration
{
string SourceDirectory { get; }
string TargetDirectory { get; }
// other primitive-typed configuration parameters
}
class FileConfiguration : IConfiguration
{
// read parameters from some config file
}
class SourceDirectoryWrapper
{
public byte[] ReadFile(string filename)
{
// read a file from the source directory
}
public string Directory { get; set; }
}
class TargetDirectoryWrapper
{
public byte[] WriteFile(string filename)
{
// write a file into the source directory
}
public string Directory { get; set; }
}
class DirectoryWrapperFactory
{
public DirectoryWrapperFactory(IConfiguration config)
{
var source = new SourceDirectoryWrapper {
Directory = config.SourceDirectory
};
var target = new TargetDirectoryWrapper {
Directory = config.SourceDirectory
};
}
}
The components FileConfiguration and DirectoryWrapperFactory can be registered as is usual.
However, what I'd like to accomplish is to somehow "outject" the source and target objects created in DirectoryWrapperFactory. The basic idea is that different environments might require different configuration providers. (And even if not, I think it's a good idea to put reading configuration parameters into a separate component.)
I'd also like to have SourceDirectoryWrapper and TargetDirectoryWrapper managed in the IoC container. In my case, mainly for convenience – I have an EventSource implementation that I need everywhere, so I inject it using property autowiring. Every object not in the IoC container needs to have it passed explicitly, which kind of bugs me.
So: is this possible with AutoFac? If so, how? I poked at the lifecycle events but most don't allow access to the registry after an object is built.
I don't quite understand why DirectoryWrapperFactory needs to exist. You could just register SourceDirectoryWrapper and TargetDirectoryWrapper directly as part of normal wireup:
builder.Register(c => new SourceDirectoryWrapper {
Directory = c.Resolve<IConfiguration>().SourceDirectory
});
builder.Register(c => new TargetDirectoryWrapper {
Directory = c.Resolve<IConfiguration>().SourceDirectory
});
Today I experienced a weird problem while trying to remotely debug an application built for the .NET 4.0 runtime.
The application resides on a network share and executed by a remote machine. However the application crashes each time during load because of a SecurityException raised by a permission demand in the System.Configuration.ConfigurationManager.GetSection() method. I have not checked if other permission demands in the base class library also cause a security exception but in all cases this shouldn't be happening with the new CLR.
The application is running in full trust (checked it while debugging and as usual this must be always true for intranet applications in CLR 4.0) so I am clueless how a permission demand can cause an exception in this case. When built against the 3.5 SP1 runtime (which first introduced full trust for network shared apps by default) everythings runs as expected.
I pasted the sample code below. Any help is greatly appreciated.
using System;
using System.Configuration;
namespace ConsoleApplication1
{
public sealed class AssetsSection : ConfigurationSection
{
private static readonly ConfigurationProperty s_propPath;
private static readonly ConfigurationPropertyCollection s_properties;
static AssetsSection()
{
s_propPath = new ConfigurationProperty("path", typeof(String));
s_properties = new ConfigurationPropertyCollection()
{
s_propPath
};
}
public static AssetsSection Get()
{
return (AssetsSection) ConfigurationManager.GetSection("test/assets");
}
protected override ConfigurationPropertyCollection Properties
{
get
{
return s_properties;
}
}
public String Path
{
get
{
return (String) base[s_propPath];
}
set
{
base[s_propPath] = value;
}
}
}
class Program
{
static void Main(String[] args)
{
Console.WriteLine(AssetsSection.Get().Path);
Console.ReadLine();
}
}
}
And the App.config file;
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="test">
<section name="assets" type="ConsoleApplication1.AssetsSection, ConsoleApplication1"/>
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/>
</startup>
<test>
<assets path="..\Assets"/>
</test>
</configuration>
Try loading the configuration first and open your section on that:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
AssetsSection configSection = (AssetsSection)config.GetSection("test/assets");
I ran into the same issue with .NET 4 and this works for me.
This is due to a known bug in .NET 4.0 when running the application from a network share.
The follow code fails with a SecurityException. Note that it only fails when you have defined a custom type for the section like in this example AssetsSection:
ConfigurationManager.GetSection("test/assets");
One fix is the solution suggestion by Timo to use a different API. Another solution is to apply the patch provided by Microsoft.
The bug and the related hotfix is filed under KB2580188.
If you add your own class to map the section like this:
[XmlRoot("Interface")]
public class MySectionClass
{
[XmlAttribute()]
public string MyAttr1
{
get;
set;
}
public string MyAttr2
{
get;
set;
}
}
You can use this code:
ConfigurationSection configSection =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).
GetSection("MySection");
XmlSerializer xs = new XmlSerializer(typeof(MySectionClass));
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(configSection.SectionInformation.GetRawXml());
XmlNodeReader xnr = new XmlNodeReader(xdoc.DocumentElement);
MySectionClass section = (MySectionClass)xs.Deserialize(xnr);
I'm speculating here, but I suspect it's your configuration file that's not trusted.
In your case, your configuration file is referencing a type ConsoleApplication1.AssetsSection that does not have a strong name that could be used as evidence.
Can you provide more details and the exact error message.