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.
Related
I want my app.config file to be something like
<configSections>
<section name ="RegCompany" type =""/>
</configSections>
<RegCompany>
<Company name="Tata Motors" code="Tata"/>
<SomethingElse url="someuri"/>
</RegCompany>
Any idea how to do this? I want to get the values defined here through my code.
For simple values like this, there is an easier solution than the one in the duplicate questions.
Config:
<configSections>
<section name="RegCompany" type="System.Configuration.NameValueSectionHandler"/>
</configSections>
<RegCompany>
<add key="CompanyName" value="Tata Motors" />
<add key="CompanyCode" value="Tata" />
<add key="CompanyUrl" value="example.com" />
</RegCompany>
Code:
var section = ConfigurationManager.GetSection("RegCompany") as NameValueCollection;
if (section == null) {
throw new InvalidOperationException("Unknown company");
}
var company = section["CompanyName"];
var code = section["CompanyCode"];
var url = section["CompanyUrl"];
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 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"/>
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.
I have the following code
var container = new UnityContainer(); //LINE 1
container.RegisterType<ILogUtility,LogUtil>(); //LINE 2
var logger = container.Resolve<Logger>(); //LINE 3
logger.Log(LogType.Warn, "logging from container"); //LINE 4
How do I implement line 2 in web.config such that I will only have to code line 1, 3, and 4 in my code behind? I have searched every where for code example but they are not clear.
Thanks
Take a look at my tutorial
http://netpl.blogspot.com/2011/11/unity-application-block-is-lightweight.html
There's an example XML configuration:
<?xml version="1.0" encoding="utf-8" ?>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<register type="ConsoleApplication30.Logic.ICustomService, ConsoleApplication30"
mapTo="ConsoleApplication30.Logic.CustomServiceImpl, ConsoleApplication30" />
</container></unity>
and you load it with
IUnityContainer container = new UnityContainer();
container.LoadConfiguration();