I have the following config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="unity1" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
<section name="unity2" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity1 configSource="unity1.config" />
<unity2 configSource="unity2.config" />
</configuration>
and the following in the unity1 file (unity2 is the same but with 2 instead of 1 in the obvious places.
<?xml version="1.0" encoding="utf-8" ?>
<unity1 xmlns="http://schemas.microsoft.com/practices/2010/unity">
<alias alias="IInjectMe1" type="CommonLib.IInjectMe1, CommonLib"/>
<container name="unity1">
<register type="IInjectMe1" name="Injected1" mapTo="CommonLib.InjectMe1, CommonLib" />
</container>
</unity1>
I have this code in a single class file in an assembly called CommonLib:
public void StartUp()
{
var config1 = (UnityConfigurationSection)ConfigurationManager.GetSection("unity1");
IUnityContainer container = new UnityContainer();
config1.Configure(container, "unity1");
var config2 = (UnityConfigurationSection)ConfigurationManager.GetSection("unity2");
config2.Configure(container, "unity2");
var test1 = container.Resolve<InjectMe1>(); // WHY NOT THE INTERFACE??
var test2 = container.Resolve<InjectMe2>(); // WHY NOT THE INTERFACE??
Console.WriteLine(test1 != null && test2 != null);
}
}
public class InjectMe1 : IInjectMe1 {}
public interface IInjectMe1 {}
public class InjectMe2 : IInjectMe2 {}
public interface IInjectMe2 {}
My question is, above where I've put "WHY NOT THE INTERFACE" why am I having to specify the concrete class instead of the interface? I'm sure it's just late and I can't see the wood for the trees, but I have to specify the concrete type and it creates the correct concrete type. I want to specify the interface and have it resolve.
I want container.Resolve<IInjectMe1>() to work. Note the I for interface.
Edit: If I do the above I get the error:
Test method CommonLib.Tests.UnitTest1.TestMethod1 threw exception:
Microsoft.Practices.Unity.ResolutionFailedException: Resolution of the dependency failed, type = "CommonLib.IInjectMe1", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, CommonLib.IInjectMe1, is an interface and cannot be constructed. Are you missing a type mapping?
Don't have the compiler at hand but I suspect you'd have to remove name="Injected1" from the XML.
By creating a named registration, you constrain yourself to named resolving. But apparently, you resolve a default registration.
Related
I am new to Unity DI ,And got stuck with an error while resolving the dependency. The error message says "The current type, Data.Core.Repository.ILogger, is an interface and cannot be constructed. Are you missing a type mapping?"
The config and code as below.
CONFIG
<configSections>
<section name="unity"
type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<assembly name ="BusinessLogic"/>
<assembly name ="Data.Core"/>
<namespace name="Data"/>
<namespace name="Data.Core"/>
<namespace name="Data.Core.Implimentation"/>
<namespace name="Data.Core.Repository"/>
<namespace name="BusinessLogic" />
<typeAliases>
<typeAlias alias="Logger1" type="Data.Core.Implimentation.Logger1,Data.Core.Implimentation" />
<typeAlias alias="Logger2" type="Data.Core.Implimentation.Logger2,Data.Core.Implimentation" />
<typeAlias alias="ILogger" type="Data.Core.Repository.ILogger,Data.Core.Repository" />
</typeAliases>
<container>
<register type="ILogger" mapTo="Logger2" name="Loggerxcs" >
</register>
</container>
Console App (front end)
var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
IUnityContainer container = new UnityContainer().LoadConfiguration(section);
// Resolving Dependancy Error is # here
LoggerBL _logger = container.Resolve<LoggerBL>();
Business Logic
// File Logger
private ILogger _logger;// = new Data.Core.Implimentation.Logger2();
public LoggerBL(ILogger logger)
{
_logger = logger;
}
public string LogToFile()
{
return _logger.LogToFile();
}
}
and Its all fine when I tried to resove the depndancy from c# code , using following
IUnityContainer container = new UnityContainer();
container.RegisterType<ILogger, Logger2>();
but when I moved the same to config I have got the above error. Thanks in advance.
The problem is that in the configuration version you have named your mapping (as "Loggerxcs").
However, your LoggerBL takes an unnamed ILogger as its parameter.
Remove
name="Loggerxcs"
From your configuration and you should be fine.
I have an application that can connect to several servers. The actual number of servers is not known until runtime,and may change from day to day. It takes several actual parameters to fully define a server.
I'm trying to configure the application using .NET support for application configurations.
The configuration file looks something like:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup
name="userSettings"
type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="server"
type="System.Configuration.SingleTagSectionHandler"
allowExeDefinition="MachineToLocalUser"
requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<server name="washington">
<add name="host" value="abc.presidents.com"/>
<add name="port" value="1414"/>
<add name="credentials" value="george"/>
</server>
<server name="adams">
<add name="host" value="def.presidents.com"/>
<add name="port" value="1419"/>
<add name="credentials" value="john"/>
</server>
<!--insert more server definitions here -->
</userSettings>
</configuration>
And I tried to read this with code something like this (the WriteLines are for diagnosing the problem. They will go away when/if it works.):
try
{
var exeConfiguration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
Console.WriteLine(exeConfiguration);
var userSettings = exeConfiguration.GetSectionGroup("userSettings");
Console.WriteLine("{0}: {1}", userSettings, userSettings.Name);
var sections = userSettings.Sections;
Console.WriteLine("{0}: {1}", sections, sections.Count);
foreach (ConfigurationSection section in sections)
{
Console.WriteLine("{0}", section);
// todo Here's where we capture information about a server
}
}
catch (System.Exception ex)
{
Console.WriteLine("Exception: {0}", ex.Message);
}
This throws an exception from the foreach and produces the following output:
System.Configuration.Configuration
System.Configuration.UserSettingsGroup: userSettings
System.Configuration.ConfigurationSectionCollection: 1
Exception: Sections must only appear once per config file. See the help topic <location> for exceptions.
If I remove the second server, leaving only washington, it "works" producing this output:
System.Configuration.Configuration
System.Configuration.ConfigurationSectionGroup: userSettings
System.Configuration.ConfigurationSectionCollection: 1
System.Configuration.DefaultSection
I've tried other variations on the theme (nested sectionGroups, etc.) without finding a solution. The various tutorial examples I've found seem to want me to create a separate class for each Server. This is obviously impractical, and should be unnecessary since all servers are created equal.
Questions:
Does System.Configuration support the concept of a collection of sets of related settings (like an array of structures)?
If so.. how?
If not.. is there another way to store persistent configuration information that does support this concept, or am I going to have to roll-my-own?
Progress Report
Based on the partial answer by Robert McKee I modified the xml like so:
<section name="servers"
type="System.Configuration.DefaultSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
and
<servers>
<add name="washington" host="abc.presidents.com" port="1414" credentials="george"/>
<add name="adams" host="def.presidents.com" port="1419" credentials="john"/>
<!--insert more server definitions here -->
</servers>
This is an improvement with one fatal problem. As you can see I changed the type attribute of the section element to name the class ystem.Configuration.DefaultSection DefaultSection succeeds at reading the configuration information (I think, at least it does not complain.) but it does not expose any way to access the information it read!
Therefore I need to use some other type of *Section class. Microsoft provides 95 classes derived from the ConfigurationSection base class, but all of them except DefaultSection and ClientSettingsSection appear to be targeted at special cases (urls, database connection strings, date and times, etc...) ClientSettingsSection won't even read the servers section -- complaining that <add/> is not a valid nested element.
So, bottom line is I'm going to have to write a custom ConfigurationSection to handle these settings. If I get it working I'll add an answer with the ultimate solution (unless someone provide a better answer first.)
Conclusions
Collections of property sets cannot be supported without creating custom property classes.
Support for creating custom property classes is pretty good.
Documentation for creating custom property classes is abysmal, however I did finally find a decent overview document that helped me find an answer.
The Configuration file
The app.config file I ended up with is:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings"
type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="executiveBranch"
type="PropProto.Properties.ExecutiveBranchSection, PropProto, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
allowExeDefinition="MachineToLocalUser"
requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<executiveBranch>
<presidents>
<president key="first"
name="George Washington"
legacy="The Fother of Our County"
/>
<president key="honestAbe"
name="Abraham Lincoln"
legacy="Freed the Slaves"
/>
<president key="who"
name="Chester Arthur"
/>
<president key="dubya"
name="George W. Bush"
legacy="Mission Accomplished!!!"
/>
<president key="barack"
name="Barack Obama"
legacy="Affordable Health Care"
/>
</presidents>
</executiveBranch>
</userSettings>
</configuration>
There is one more nesting level than I had expected (or want). That's because presidents is a ConfigurationElementCollection and userSettings cannot include a ConfigurationElementCollection directly, so I had to introduce executiveBranch.
Using the Configuration
The code to read these settings is:
var exeConfiguration = ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.PerUserRoamingAndLocal);
var userSettings = exeConfiguration.GetSectionGroup("userSettings");
var executiveBranch = (ExecutiveBranchSection)userSettings.Sections.Get(
ExecutiveBranchSection.Tag);
var presidents = executiveBranch.Presidents;
foreach (President president in presidents)
{
Console.WriteLine("{0}: {1}", president.Name, president.Legacy);
}
The Custom Properties Classes
And the custom classes to make all this work:
public class ExecutiveBranchSection : ConfigurationSection
{
public const string Tag = "executiveBranch";
[ConfigurationProperty(PresidentCollection.Tag)]
public PresidentCollection Presidents { get { return (PresidentCollection)base[PresidentCollection.Tag]; } }
}
[ConfigurationCollection(typeof(President),
CollectionType = ConfigurationElementCollectionType.BasicMap,
AddItemName = President.Tag)]
public class PresidentCollection : ConfigurationElementCollection
{
public const string Tag = "presidents";
protected override string ElementName { get { return President.Tag; } }
public President this[int index]
{
get { return (President)base.BaseGet(index); }
set
{
if (base.BaseGet(index) != null)
{
base.BaseRemoveAt(index);
}
base.BaseAdd(index, value);
}
}
new public President this[string name] { get { return (President)base.BaseGet(name); } }
protected override ConfigurationElement CreateNewElement()
{
return new President();
}
protected override object GetElementKey(ConfigurationElement element)
{
return (element as President).Key;
}
}
public class President : ConfigurationElement
{
public const string Tag = "president";
[ConfigurationProperty("key", IsRequired = true)]
public string Key { get { return (string)base["key"]; } }
[ConfigurationProperty("name", IsRequired = true)]
public string Name { get { return (string)base["name"]; } }
[ConfigurationProperty("legacy", IsRequired = false)]
public string Legacy { get { return (string)base["legacy"]; } }
}
Haven't worked with custom config sections, but from a purely logical point of view, isn't this more appropriate:
<userSettings>
<servers>
<add name="washington" host="abc.presidents.com" port="1414" credentials="george"/>
<add name="adams" host="def.presidents.com" port="1419" credentials="john"/>
<!--insert more server definitions here -->
</servers>
<!-- insert more user settings here -->
</userSettings>
You can do it other ways, but if you want a collection of "server", then it must be in a grouping element like "servers". You can't just have multiple "server" in a parent element that can also contain other types of children. The tag within the group is almost always "add".
In any case "System.Configuration.SingleTagSectionHandler" definitely is not the correct type.
I have an application that uses unity FW to resolve objects throughout.
I have done some change to the framework and the classes which can be seen in the code comment as "NEW CHANGE"
The wrapper class looks like
public static class ContractResolver
{
public static T Resolve<T>() //This is been used in many places in application
{
IUnityContainer container = new UnityContainer();
var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(container);
return container.Resolve<T>();
}
//NEW CHANGE: This is the new function that suppose to return the instance of parameterised constructor
public static T Resolve<T>(ParameterOverride[] parameterOverrides)
{
IUnityContainer container = new UnityContainer();
var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(container);
return container.Resolve<T>(parameterOverrides);
}
}
The configuration looks like
<unity>
<containers>
<container>
<types>
<type type ="UnityTest.IImageRepositoryService, UnityTest" mapTo="UnityTest.ImageRepositoryService, UnityTest"/>
</types>
</container>
</containers>
</unity>
The classes and interface looks like
public interface IImageRepositoryService
{
bool Exists(string imageName);
}
public class ImageRepositoryService : IImageRepositoryService
{
private readonly string mFilterName = "StandardImageFilter";
//[InjectionConstructor]
public ImageRepositoryService()
{
DatabaseQueryProvider.Query("Image", mFilterName);
}
//NEW CHANGE. A CONSTRUCTOR THAT ACCEPTS A PARAMETER
//[InjectionConstructor]
public ImageRepositoryService(string filterName)
{
mFilterName = filterName;
DatabaseQueryProvider.Query("Image", filterName);
}
public bool Exists(string imageName)
{
Console.WriteLine("The image " + imageName + " found in filter " + mFilterName);
return true;
}
}
The usage looks like
var serviceDefault = ContractResolver.Resolve<IImageRepositoryService>();
serviceDefault.Exists("myimage.bmp");
The new changes breaks the old usage. i.e.
var serviceDefault = ContractResolver.Resolve<IImageRepositoryService>();
Throws exception
Resolution of the dependency failed, type = "UnityTest.IImageRepositoryService", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The type String cannot be constructed. You must configure the container to supply this value.
I would like to have the new functionality at the same time do not want to break the old functionality.
var serviceDefault = ContractResolver.Resolve<IImageRepositoryService>();
serviceDefault.Exists("myimage.bmp");
Should display the message in the console "The image myimage.bmp found in filter StandardImageFilter"
var parameterOverride1 = new ParameterOverride("filterName", "filter1");
var servicefilter1 = ContractResolver.Resolve<IImageRepositoryService>(new[] { parameterOverride1 });
servicefilter1.Exists("myimage.bmp");
Should display the message in the console "The image myimage.bmp found in filter filter1"
var parameterOverride2 = new ParameterOverride("filterName", "filter2");
var servicefilter2 = ContractResolver.Resolve<IImageRepositoryService>(new[] { parameterOverride2 });
servicefilter2.Exists("myimage.bmp");
Should display the message in the console "The image myimage.bmp found in filter filter2"
How solve this problem?
If you want to resolve the same type (in this case IImageRepositoryService) but have different calls to Resolve invoke different constructors then you will need to use named registrations.
In your case you can do this in the XML configuration:
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<register type ="UnityTest.IImageRepositoryService, UnityTest" mapTo="UnityTest.ImageRepositoryService, UnityTest">
<constructor />
</register>
<register name="ParameterizedRepository"
type="UnityTest.IImageRepositoryService, UnityTest"
mapTo="UnityTest.ImageRepositoryService, UnityTest">
<constructor>
<param name="filterName" value="dummyValue" />
</constructor>
</register>
</container>
</unity>
Note, that I've used the Unity 2 (and 3) configuration style.
So this tells Unity that when resolving using the name "ParameterizedRepository" to invoke the constructor with the parameter named "filterName". I've used a dummy value here because we are going to override the value at runtime anyway:
var imageRepositoryService = container.Resolve<IImageRepositoryService>(
"ParameterizedRepository",
new ParameterOverride("filterName", "filter2"));
So that's how to get what you want using Unity so in terms of your wrapper class you should add a name parameter:
public static class ContractResolver
{
//NEW CHANGE: This is the new function that suppose to return the instance of parameterised constructor
public static T Resolve<T>(string name, params ParameterOverride[] parameterOverrides)
{
IUnityContainer container = new UnityContainer();
var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(container);
return container.Resolve<T>(name, parameterOverrides);
}
}
A few unsolicited comments (in the spirit of trying to be helpful):
It looks like you are using Unity version 1. If so, you might want to consider upgrading (version 3 was released recently) and if you are not using Unity version 1, then you might want to consider changing the XML configuration syntax to use the newer approach as well as using the LoadConfiguration() extension method.
I'm not sure why every call to ContractResolver.Resolve() creates a new Unity container and then loads the configuration. This could be a bit of a performance hit. Usually, you would create a container and load the configuration once and use that instance for the lifetime of the application.
I can understand how you would be tempted to hide the container implementation behind the ContractResolver but with the addition of ParameterOverride (which are Unity specific) the abstraction is becoming a bit leaky.
I have a dot.NET 4.0 web application with a custom section defined:
<configuration>
<configSections>
<section name="registrations" type="System.Configuration.IgnoreSectionHandler, System.Configuration, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="true" restartOnExternalChanges="true" allowLocation="true"/>
....
at the end of the web.config file I have the respective section:
....
<registrations>
.....
</registrations>
</configuration>
Every time I call System.Configuration.ConfigurationManager.GetSection("registrations"); I get the following exception:
An error occurred creating the configuration section handler for registrations: The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047) (C:\...\web.config line 13)
I'm also using Unity but don't know if that's in any way related to the error.
Have you faced this error before? How can I fix it? Do I need to replace the IgnoreSectionHandler with something else?
Given this app.config:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="registrations" type="MyApp.MyConfigurationSection, MyApp" />
</configSections>
<registrations myValue="Hello World" />
</configuration>
Then try using this:
namespace MyApp
{
class Program
{
static void Main(string[] args) {
var config = ConfigurationManager.GetSection(MyConfigurationSection.SectionName) as MyConfigurationSection ?? new MyConfigurationSection();
Console.WriteLine(config.MyValue);
Console.ReadLine();
}
}
public class MyConfigurationSection : ConfigurationSection
{
public const String SectionName = "registrations";
[ConfigurationProperty("myValue")]
public String MyValue {
get { return (String)this["myValue"]; }
set { this["myValue"] = value; }
}
}
}
You are missing the Namespace in the type attribute of your section in App.Config. Infact you dont need the full assembly info in there either. only the namespace is enough
Updated 1
yourcustomconfigclass config =(yourcustomconfigclass)System.Configuration.ConfigurationManager.GetSection(
"registrations");
and in config file only write
<section name="registrations" type="System.Configuration.IgnoreSectionHandler" requirePermission="true" restartOnExternalChanges="true" allowLocation="true"/>
<configuration>
<configSections>
<sectionGroup name="loggingConfigs">
<section name="LoggingParameters"
type="Framework.Logging.LoggingParameters, Framework.Logging" />
</sectionGroup>
</configSections>
<loggingConfigs>
<LoggingParameters
myconfig="C:mydir\mypath1\mypath2\log4net.config"
/>
</loggingConfigs>
</configuration>
public class LoggingParameters : ConfigurationSection
{
[ConfigurationProperty("myconfig", IsRequired = true)]
private string ConfigFileLoc
{
get { return (string)this["myconfig"]; }
}
public FileInfo MyConfigFile
{
get
{
string s = ConfigFileLoc; <--- getting empty string here..don't know why
return new FileInfo(s);
}
}
}
When I make the following call else where in my application,
FileInfo f = new Framework.Logging.LoggingParameters().MyConfigFile;
the ConfigFileLoc always comes back as blank. I can not figure out why its blank.. why the string is empty.. please help.
I had to remove the SectionGroup (don't know if that is a requirement for you)
<configSections>
<section name="LoggingParameters"
type="Framework.Logging.LoggingParameters, Framework.Logging" />
</configSections>
<LoggingParameters myconfig="C:mydir\mypath1\mypath2\log4net.config" />
And got the FileInfo with this code (path is not empty anymore)
LoggingParameters config = (LoggingParameters)ConfigurationSettings.GetConfig("LoggingParameters");
FileInfo fInfo = config.MyConfigFile;
This post by Scott Mitchell may help you
I would avoid writing configuration access code by hand. It's too easy to foobar. Check out this addin that lets you visually design your configurations. Let it write the boilerplate code for you while you focus solely on the visual designer and your problem domain.
http://csd.codeplex.com/