Unrecognized attribute "Default" (UnityConfigurationSection)

Feb 14, 2008 at 2:35 AM
I'm trying to use an app.config to inject dependencies. I am using the quickstart for the Stoplight app. Here is my error, code and config (any help would be appreciated):

-- Exception --

System.Configuration.ConfigurationErrorsException was unhandled
Message="Unrecognized attribute 'Default'. Note that attribute names are case-sensitive. (C:\\Users\\...\\Unity\\Unity\\QuickStarts\\Stoplight\\Src\\bin\\Debug\\StopLight.vshost.exe.Config line 12)"
Source="System.Configuration"
BareMessage="Unrecognized attribute 'Default'. Note that attribute names are case-sensitive."
Filename="C:\\Users\\...\\Unity\\Unity\\QuickStarts\\Stoplight\\Src\\bin\\Debug\\StopLight.vshost.exe.Config"
Line=12
StackTrace:
at System.Configuration.BaseConfigurationRecord.EvaluateOne(String[] keys, SectionInput input, Boolean isTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult)
at System.Configuration.BaseConfigurationRecord.Evaluate(FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult, Boolean getLkg, Boolean getRuntimeObject, Object& result, Object& resultRuntimeObject)
at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
at System.Configuration.BaseConfigurationRecord.GetSection(String configKey, Boolean getLkg, Boolean checkPermission)
at System.Configuration.BaseConfigurationRecord.GetSection(String configKey)
at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName)
at System.Configuration.ConfigurationManager.GetSection(String sectionName)
at StopLight.Program.Main() in C:\Users\...\Unity\Unity\QuickStarts\Stoplight\Src\Program.cs:line 40
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:

-- in Program.cs --

IUnityContainer container = new UnityContainer();
UnityConfigurationSection section
= (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.GetConfigCommand().Configure(container);

-- add app.config to project --

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

<configSections>
<section name="unity"
type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration" />
</configSections>

<unity>

<containers Default="containerOne">

<container name="containerOne">

<types>
<add name="MyType1" type="ILogger"
mapTo="NullLogger" />
<add name="MyType2" type="IStoplightTimer"
mapTo="RealTimeTimer" />
</types>

<instances>
<add name="MyInstance1" type="System.String" value="Some value" />
<add name="MyInstance2" type="System.DateTime" value="2008-02-05T17:50:00" />
</instances>

<extensions>
<add type="MyApp.MyExtensions.SpecialOne" />
</extensions>

</container>

<container name="containerTwo">
<types>
<add name="MyType1" type="ILogger"
mapTo="TraceLogger" />
<add name="MyType2" type="IStoplightTimer"
mapTo="RealTimeTimer" />
</types>
</container>
</containers>

</unity>

</configuration>

Feb 14, 2008 at 8:14 AM
Edited Feb 14, 2008 at 9:40 AM
Although documented, the source does not support the "Default" containers attribute. Also, the "add" sub element of types needs to renamed to type.

Use the following configuration:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>

<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>

<unity>
<containers>
<container>
<types>
<type type="StopLight.ServiceInterfaces.ILogger, StopLight" mapTo="StopLight.ServiceImplementations.TraceLogger, StopLight" />
<type type="StopLight.ServiceInterfaces.IStoplightTimer, StopLight" mapTo="StopLight.ServiceImplementations.RealTimeTimer, StopLight" />
</types>
</container>
</containers>
</unity>

</configuration>

And then modify the main method of the application to:
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

IUnityContainer container = new UnityContainer();

UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.GetConfigCommand().Configure(container);

Application.Run(container.Get<StoplightForm>());
}
Feb 14, 2008 at 12:39 PM
Thanks! - I got it working, I should have also figured also that the types would also need to be in the format of fully qualified type, assembly name also. Great stuff. I tried with multiple containers (using the name attribute for the container), and that works. Will the Default attribute be implemented (I can do it myself, just wanted to know if it was on the list).
Feb 14, 2008 at 7:30 PM
There's a little confusion here in the docs, and brings up some good usability questions we need to investigate.

The Containers configuration element does have a Default property, but it's not one that's represented in the config file itself. Instead, the Default property gives you the first container that doesn't have a name specified. Much like with Unity itself.

Should we change this?

-Chris
Feb 15, 2008 at 2:55 AM
I wouldn't focus your time on it now, if there are larger fish to fry. I'm sure the early adopters can get it to work (I'm looking at modding the code by adding ConfigurationPropertyAttribute and whatever config code that we need). Maybe backlog it, and you can get to it. However, I would change the document as soon as you can and include a Quickstart with a config file. I've done the Spring framework, and that's a healthy dose of config files - the only way to get started with any reasonable assurance was to follow the tutorials, RTFM and get a reference example.