Configuring Unity From FileConfigurationSource

Feb 28, 2009 at 1:36 PM
Using Enterprise library 4.1.

I have an app.config defined in AProject, with configuration for a unity container, the logging application block and exception policies.

I have an MS test project, AProjectTest, which deploys AProject.app.config to a folder 'MYFOLDER' during the test:
So it is deployed to:
C:\Dev\Solution\~\username_E29388 2009-02-27 10_49_56\Out\MYFOLDER\AppConfig

I then create a file configuration source:
IConfigurationSource configSource = new FileConfigurationSource( "path" );
UnityConfigurationSection unityConfigurationSection = (UnityConfigurationSection)configurationSource.GetSection("unity");

var unityContainer = new UnityContainer();
unityConfigurationSection.Containers.Default.Configure(unityContainer);

// Then when I try and resolve a type configured in the config, it throws an exception:
var logWriter = unityContainer.Resolve<LogWriter>();

This works if I add app.config to the root in my AProjectTest, and read in that file using the same technique above. Of course, it gets renamed to MyTestProject.dll.config.

Here is the stack trace:
Stack trace: Failed    CanConnectToFullAuthAndExecuteQuery1Test    TarongEnergy.Trading.Services.DataBroker.Tests    Class Initialization method TarongEnergy.Trading.Services.DataBroker.Data.Tests.MarketMessagesDataAdapterTest.ClassInitialize threw exception. Microsoft.Practices.Unity.ResolutionFailedException:  Microsoft.Practices.Unity.ResolutionFailedException: Resolution of the dependency failed, type = "Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter", name = "". Exception message is: The current build operation (build key Build Key[Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter, null]) failed: The parameter filters could not be resolved when attempting to call constructor Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter(System.Collections.Generic.ICollection`1[[Microsoft.Practices.EnterpriseLibrary.Logging.Filters.ILogFilter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]] filters, System.Collections.Generic.IDictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[Microsoft.Practices.EnterpriseLibrary.Logging.LogSource, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]] traceSources, Microsoft.Practices.EnterpriseLibrary.Logging.LogSource allEventsTraceSource, Microsoft.Practices.EnterpriseLibrary.Logging.LogSource notProcessedTraceSource, Microsoft.Practices.EnterpriseLibrary.Logging.LogSource errorsTraceSource, System.String defaultCategory, System.Boolean tracingEnabled, System.Boolean logWarningsWhenNoCategoriesMatch, System.Boolean revertImpersonation). (Strategy type BuildPlanStrategy, index 3) --->  Microsoft.Practices.ObjectBuilder2.BuildFailedException: The current build operation (build key Build Key[Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter, null]) failed: The parameter filters could not be resolved when attempting to call constructor Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter(System.Collections.Generic.ICollection`1[[Microsoft.Practices.EnterpriseLibrary.Logging.Filters.ILogFilter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]] filters, System.Collections.Generic.IDictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[Microsoft.Practices.EnterpriseLibrary.Logging.LogSource, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]] traceSources, Microsoft.Practices.EnterpriseLibrary.Logging.LogSource allEventsTraceSource, Microsoft.Practices.EnterpriseLibrary.Logging.LogSource notProcessedTraceSource, Microsoft.Practices.EnterpriseLibrary.Logging.LogSource errorsTraceSource, System.String defaultCategory, System.Boolean tracingEnabled, System.Boolean logWarningsWhenNoCategoriesMatch, System.Boolean revertImpersonation). (Strategy type BuildPlanStrategy, index 3) --->  System.InvalidOperationException: The parameter filters could not be resolved when attempting to call constructor Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter(System.Collections.Generic.ICollection`1[[Microsoft.Practices.EnterpriseLibrary.Logging.Filters.ILogFilter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]] filters, System.Collections.Generic.IDictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[Microsoft.Practices.EnterpriseLibrary.Logging.LogSource, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]] traceSources, Microsoft.Practices.EnterpriseLibrary.Logging.LogSource allEventsTraceSource, Microsoft.Practices.EnterpriseLibrary.Logging.LogSource notProcessedTraceSource, Microsoft.Practices.EnterpriseLibrary.Logging.LogSource errorsTraceSource, System.String defaultCategory, System.Boolean tracingEnabled, System.Boolean logWarningsWhenNoCategoriesMatch, System.Boolean revertImpersonation). --->  Microsoft.Practices.ObjectBuilder2.BuildFailedException: The current build operation (build key Build Key[System.Collections.Generic.ICollection`1[Microsoft.Practices.EnterpriseLibrary.Logging.Filters.ILogFilter], null]) failed: The current type, System.Collections.Generic.ICollection`1[Microsoft.Practices.EnterpriseLibrary.Logging.Filters.ILogFilter], is an interface and cannot be constructed. Are you missing a type mapping? (Strategy type BuildPlanStrategy, index 3) --->  System.InvalidOperationException: The current type, System.Collections.Generic.ICollection`1[Microsoft.Practices.EnterpriseLibrary.Logging.Filters.ILogFilter], is an interface and cannot be constructed. Are you missing a type mapping?.       
Feb 28, 2009 at 2:11 PM
Hi KierenH,

I see you were referred here from the EnterpriseLibrary Discussion area (reference http://entlib.codeplex.com/Thread/View.aspx?ThreadId=48690).

I believe the key to your problem lies in the last few lines of the error message:

The current type, System.Collections.Generic.ICollection`1[Microsoft.Practices.EnterpriseLibrary.Logging.Filters.ILogFilter], is an interface and cannot be constructed. Are you missing a type mapping?

I see this quite a bit particularly since I use configuration files to configure my Unity Container(s).   Usually the error is right on track and I did in fact fail to map a type to the specified interface.   The above is telling us that Unity cannot resolve the "ILogFilter".   When you use the EnterpriseLibrary's "FileConfigurationSource" command Unity will attempt to resolve this interface and crash, when you are using the "App.Config" the EnterpriseLibrary is not in the loop (ILogFilter is not being resovled) and it works - as you suggested.

I would first search the documentation for this to find out if you are required to configure an ILogFilter for the EnterpriseLibrary.   Next, if your search fails I would rephrase your question in the EnterpriseLibrary discussion area to ask how you configure [Microsoft.Practices.EnterpriseLibrary.Logging.Filters.ILogFilter] so that Unity can resolve it.

Bill
Feb 28, 2009 at 10:49 PM
Hi Bill

The logging application block and unity container is configured correctly - including the App.config from ProjectA in ProjectATest and calling:

IConfigurationSource configSource = new SystemConfigurationSource();
UnityConfigurationSection unityConfigurationSection = (UnityConfigurationSection)configurationSource.GetSection("unity");

var unityContainer = new UnityContainer();
unityConfigurationSection.Containers.Default.Configure(unityContainer);

// Passes
var logWriter = unityContainer.Resolve<LogWriter>();

Is there anymore information I can provide, eg, the configuration file.

Kieren
Feb 28, 2009 at 11:44 PM
Yes, please provide the configuration file.  Currently, in my http://www.CodePlex.com/SDMS application's MockBootStrapper I have a homegrown version of the  FileConfigurationSource() that I use to read in the Web.Config file (of the primary application) so that my entire solution, i.e., ASP.NET, Silverlight, Desktop and WCF, all share the same configuration file.  

The EntLib 4.1, and FileConfigurationSource(), lends itself to my "one configuration file for my entire enterprise solution" goal.    What I want to try is to have my WCF service (Unity Behavior) read in the primary Web Sites Web.Config for it's information - since I'm programming in a Multi-targeting environment (one code base for Desktop and Silverlight) this could work very nicely.

I'm going to plug in the EntLib into SDMS and one of two things will happen when I use FileConfigurationSource() to resolve LogWriter using your configuration - I'll either run into the problem you are having - or it will work.   Either way I will be able to help you resolve your issue :)  

Bill
Mar 1, 2009 at 12:19 AM
Hi KierenH,

Just curious - is there a reason you are attempting to resolve LogWriter?  I just finished reviewing the documentation for "Logging QuickStart" walkthroughs and it seems we're off the beaten path, i.e., haven't seen anything that uses the LogWriter directly (requiring us to configure it's parameters).

Typically we only resolve classes when we want to take advantage of DI from within that class, generally we resolve interfaces.   

Would help for me to understand the context of your objectives.

Bill
  
Mar 1, 2009 at 2:31 AM

Something to try, the following is from the Documentation:
 + Developing Applications with Enterprise Library
    + Adding Enterprise Library to Applications
       + Creating Application Block Objects
           + Creating Objects Using the Application Block 

By default, this extension will read its configuration from the application configuration file (App.config or Web.config). If you want to provide a custom configuration source, you create this first and pass it to the EnterpriseLibraryCoreExtension as shown in the following code.

C#
IUnityContainer uContainer = new UnityContainer();
IConfigurationSource configSource = new MyCustomConfigSource();
// ... populate configuration source as required here
uContainer.AddExtension(new EnterpriseLibraryCoreExtension(configSource));

More stuff....

You can then load the Enterprise Library core extension and the Logging Application Block extension into a Unity container, and then you can instantiate the custom class complete with the injected reference to the LogWriter class, as shown in the following code.

C# Copy Code 
IUnityContainer uContainer = new UnityContainer();
uContainer.AddNewExtension<EnterpriseLibraryCoreExtension>();
uContainer.AddNewExtension<LoggingBlockExtension>();
MyNewObject myNewInstance = uContainer.Resolve<MyNewObject>();

 

Mar 1, 2009 at 4:17 AM
Hi Bill

Thanks for your help so far. I shouldn't have to setup the extensions in code because it comes from the config file:

  <unity>
    <containers>
      <container>
        <extensions>
          <add type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Unity.EnterpriseLibraryCoreExtension, Microsoft.Practices.EnterpriseLibrary.Common" />
          <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.Unity.LoggingBlockExtension, Microsoft.Practices.EnterpriseLibrary.Logging" />
...
</unity>

The class I am testing would traditionally have a dependency on the static class Logger. The problem with this approach is that you can't specify logging configuration other than what is in the App.config.
Making my class dependent on the instance based LogWriter provides more flexibility for configuring logging.

public class MyClass
{
    public void DoSomething()
    {
        if ( Logger.IsLOggingENabled() )
       {
        ...
        }
    }

    [Dependency]
    public LogWriter LogWriter { Get; set; }
}

For the purpose of my test, I resolve the type "MyClass" from the UnityContainer... and it should build up the object tree, and resolve LogWriter according to the configuration it reads.

Now, the reason I Manually resolve LogWriter:
var logWriter = uContainer.Resolve<LogWriter>();
is because in my test, I want to override some of the configuration, eg:
logWriter.GetFilter<LogEnabledFilter>().IsEnabled = false;

To try and help you visualize my scenario a little better, here is the structure of the projects (Trying to resolve LogWriter in this scenario fails):
Root Folder
.sln file
-ProjectA
--App.config

-ProjectATest
--My Folder
---[App.config from ProjectA included in the project as a link]

NOTE: The config is read cleanly.

            string appConfigPath = Path.Combine(testContext.TestDeploymentDir, "my folder\app.config"));

            IConfigurationSource configurationSource = new FileConfigurationSource(appConfigPath);

            // Will throw an exception if the configuration element does not exist
            UnityConfigurationSection unityConfigurationSection = (UnityConfigurationSection)configurationSource.GetSection("unity");

            // Create a new unity container and configure it from config source
            var unityContainer = new UnityContainer();
            unityConfigurationSection.Containers.Default.Configure(unityContainer);

            // Turn off logging
            var logWriter = unityContainer.Resolve<LogWriter>();

            logWriter.GetFilter<LogEnabledFilter>().Enabled = false;
            return unityContainer;

______________
To get it to work, I have had to structure the projects like this:
Root Folder
.sln file
-ProjectA
--App.config

-ProjectATest
--[App.config from ProjectA included in the project as a link]


            string appConfigPath = Path.Combine(testContext.TestDeploymentDir, String.Format("{0}.dll.config", Assembly.GetExecutingAssembly().GetName().Name));

            IConfigurationSource configurationSource = new FileConfigurationSource(appConfigPath);

            // Will throw an exception if the configuration element does not exist
            UnityConfigurationSection unityConfigurationSection = (UnityConfigurationSection)configurationSource.GetSection("unity");

            // Create a new unity container and configure it from config source
            var unityContainer = new UnityContainer();
            unityConfigurationSection.Containers.Default.Configure(unityContainer);

            // Turn off logging
            var logWriter = unityContainer.Resolve<LogWriter>();

            logWriter.GetFilter<LogEnabledFilter>().Enabled = false;
            return unityContainer;

---


Mar 1, 2009 at 4:41 PM
Makes sense now.  Getting ready to leave for chuch and will be assisting the wife today at an event but am going to bring my laptop in case I get time to play.   Sounds like you have your T's crossed and your I's dotted; this will be an excellent learning exercise (and a fun challenge).  I'll let you know.
Mar 1, 2009 at 9:34 PM
I got a weak internet connection and my laptop doesn't have VS2008 (dough!) but I'm able to remote into my development server.   Wondering how the Unit Test were able to accomplish the task at hand I found the following - have you tried this?   

Logging.Tests.VSTS
+ LogWriterFixture.cs


     [TestMethod]
        public void CanCreateLogWriterUsingFactory()
        {
            LogWriter writer = EnterpriseLibraryFactory.BuildUp<LogWriter>();
            Assert.IsNotNull(writer);
        }
Mar 2, 2009 at 8:32 AM
Do I have to setup anything to get the tests to work?
Right-clicking and running the test in context... the test failed.
Mar 2, 2009 at 2:43 PM
Time to move this discussion back to Enterprise Library KierenH!

If the Unit Test are failing then we are pretty much dead in the water (can't solve a problem until the infrastructure is working properly)...  I trust when this unit test passes your problem will be resolved as you'll have your LogWriter instance.

I originally thought the problem with running the test were because the system was being overwhelmed with the large number of test projects (even though I have dual core, x64 and 3 gig of RAM). So I unloaded all but the logging test projects and verified what you found - the unit test fails for a readonly error in the performance counter (failed during the constructor).   When I placed a break point and attempted again I got a dreaded manifest error.  I also found many of the other test failing.... not good....  This is with Enterprise Library 4.1 right out of the box, compiled and attempting to run the unit test.

Signing out on this one - to much on my plate to fight infrastructure issues.  Please let me know when Unit Test are working (I trust you'll be on them about this) so I can try EntLib4.1 again.

Was fun :)
Bill


Mar 2, 2009 at 8:16 PM
Odd how things work out sometimes...  We're starting a new project/sprint today and I was assigned logging and exception handling - go figure :)   Needless to say, before I make the deterimination to not use EntLib 4.1 I'll have to do due diligence.     What I've found so far (lucky guess) was by running the "Install Instrumentation" menu option (under Microsoft Practices & Patterns | Enterprise Library) my unit test now initialize without failure; it gets past TestInitialization and into the Unit Test without failure; now if I can just get it to run without VS going "not responding" - work in progress.
Mar 2, 2009 at 10:36 PM
Found the problem with the Enterprise Library 4.1 unit test and I can successfully run the code that should resolve your issue:

     [TestMethod]
        public void CanCreateLogWriterUsingFactory()
        {
            LogWriter writer = EnterpriseLibraryFactory.BuildUp<LogWriter>();
            Assert.IsNotNull(writer);
        }

Blogged about on the following link.
http://www.global-webnet.net/blogengine/post/2009/03/02/Enterprise-Library-41-unit-test-dont-work.aspx
Mar 4, 2009 at 10:21 AM
Hi Bill

I didn't think they'd ship failing unit tests :)

Why do I need to tell it to build up? (uContainer.BuildUp<Type>)

I expect(ed) that configuring the unity container, would essentially do that, and allow me to get a type:
uContainer.Resolve<Type>();

If you look at my work-around, I don't need to do build-up...
Root Folder
.sln file
-ProjectA
--App.config

-ProjectATest
--[App.config from ProjectA included in the project as a link]

Cheers
Kieren
Mar 4, 2009 at 12:51 PM
Edited Mar 4, 2009 at 12:52 PM
[kierenH] I didn't think they'd ship failing unit tests :)

Yep, been keeping me pretty busy particularly since the Unit Test are my starting point for learning new P&P projects.   I decided to go with EntLib 4.1 (more because of the great support than the confidence in it's ability to do the job) combined with Interception (because of a polymorphic infrastructure) and I spend more time fixing Unit Test then I do achieving my objectives.  Unfortunately, I "have" to determine why they are failing before I trust our production code to it.  Besides, we can't anticipate TDD to go well when the out-of-the-box stuff is failing... 

[kierenH] Why do I need to tell it to build up? (uContainer.BuildUp<Type>)

Dough!!  I missed that you had a work-around :)  Great!

I'll keep this one book marked as Logging, Validation and Exception handling are on my plate for this sprint.
Mar 4, 2009 at 6:21 PM
Bill, maybe you should ask the dev lead on Enterprise Library for help. I'm sure if he saw the failures you're getting he'd be able to get you running much more quickly.

If only we knew who that person is. ;-)

-Chris
Mar 4, 2009 at 7:14 PM

@Chris, thanks but it’s too early in the game to be showing off my ignorance ;)    

 

Being a newbie to EntLib 4.1 it’s hard to determine whether an issue is my failure to use existing documentation/resources (should be digging deeper) or an actual problem.   Remember the questions I use to bring to this forum in my ignorance (in the early days) – I trust it required a lot of patience on your part…

 

Many of the EntLib problems were environmental (running out of resources) and a few configuration.  I understand the configuration issues because I ran into this with EntLib 3.1 whenever I used the Enterprise Configuration utility – it would default to the .DLLs and I was referencing code projects;  I had to remove these references any time I used the tool. 

 

Another factor is my bleeding box – it’s on the bleeding edge so it places an extra burden on me to isolate issues. i.e., remember when I reported that Unity Test that failed because  of something like the following (can’t remember exactly):

 

try {

   // did something here

} catch {}

 

.NET Documentation showed it should work so technically your Unit Test was correct  - but it was crashing.   You asked the question if I had  .Net 3.5 Sp1 beta installed (which I did) so I moved on.

 

Ultimately, I learn more by the search and destroy missions.  When the smoke settles and I have confirmed issues I’ll find the Dev Lead (whoever that is;) and report them and we can sift through what’s bleeding (Windows 7, x64, SQL Server 2008,  Windows Server 2008 R2 domain, etc) and what’s real.

 

Bill

May 20, 2009 at 1:02 PM

See: http://unity.codeplex.com/Thread/View.aspx?ThreadId=56864
For better walk-through of the problem and explanation.