Do you have a sample application with policy injection for EntLib 5.0?

Topics: Logging Application Block, Policy Injection Application Block
Oct 26, 2010 at 7:19 AM

I've been trying to configure policy injection for my WCF service but can't get it working.  I'd really like to see a complete application with policy injection, ideally with LogCallHandler but anything might help.

The Dev Guide has been really useful with the other blocks - is there a plan to add a policy injection section to it?

Oct 26, 2010 at 7:48 AM
Edited Oct 26, 2010 at 8:08 AM

I'm not sure if there's a plan on this since Policy Injection in version 5.0 is now just one of the ways you can do interception in Unity.   We'll confirm this with the EntLib team.

I don't have any sample application for this but you could probably try converting this in the latest version.

By the way, if you're interested in doing this using Unity, a discussion on this can be found on this thread.  The API that was used is the 1.2 version so there are things which can be modified to use the 2.0 version.  Additionally, you can post it in the Unity forum.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Oct 26, 2010 at 9:40 PM
Edited Oct 27, 2010 at 7:33 AM

Thanks for the reply.  I've read the Unity pages in the .chm but I still don't understand what's required.  I accept that it's up to the Unity team to write the guide on Unity Interception but unless I'm completely misunderstanding things, that wouldn't be the complete picture - the EntLib team would still need to cover their policy injection stuff.

I appreciate the pointers to the EntLib 4.1 and Unity 1.2 stuff but given how much has changed in both, I think I'll only end up more confused if I look at those.

And the problem with posting in the Unity forum is that I don't really understand what's theirs and what's yours.  To be frank, I don't want to go near Unity interception.  I just want to slap a LogCallHandler attribute on my classes and have it work:

[LogCallHandler(Categories = new string[] { "Tracing" },
    LogAfterCall = true, LogBeforeCall = true,
    BeforeMessage = "Eggs", AfterMessage = "And Chips",
    EventId = 42, Priority = 1)]


I'm going to start from scratch with a new test app and see how I get on.

Oct 27, 2010 at 6:14 AM
Edited Oct 27, 2010 at 6:15 AM

So, I've started my sample app.  It's a Console Application.  I've added the following references to it:

    Microsoft.Practices.EnterpriseLibrary.Common
    Microsoft.Practices.EnterpriseLibrary.ExceptionHandling
    Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging
    Microsoft.Practices.EnterpriseLibrary.Logging
    Microsoft.Practices.EnterpriseLibrary.Logging.Database
    Microsoft.Practices.EnterpriseLibrary.PolicyInjection
    Microsoft.Practices.ServiceLocation
    Microsoft.Practices.Unity
    Microsoft.Practices.Unity.Configuration
    Microsoft.Practices.Unity.Interception
    Microsoft.Practices.Unity.Interception.Configuration
    System
    System.configuration
    System.Core
    System.Xml.Linq
    System.Data.DataSetExtensions
    Microsoft.CSharp
    System.Data
    System.Xml

The Target Framework is the full .NET Framework 4 - this one caught me out again for a few minutes, when I failed to spot the warning message.

The Assembly Name and Default Namespace are both PolicyInjection1.

I have a class file called Widget.cs which contains:

using Microsoft.Practices.EnterpriseLibrary.Logging;

namespace PolicyInjection1
{
    public class Widget : IWidget
    {
        private LogWriter logWriter;
        private int flangeCount;

        public Widget(LogWriter logWriter)
        {
            this.logWriter = logWriter;

            LogEntry entry = new LogEntry("Default .ctor", "General", 1, 401, 
                System.Diagnostics.TraceEventType.Information, "Woo", null);
            
            logWriter.Write(entry);
        }

        public int GetFlangeCount()
        {
            return this.flangeCount;
        }

        public void SetFlangeCount(int count)
        {
            this.flangeCount = count;
        }

        public int FlangeCount
        {
            get { return this.flangeCount; }
            set { this.flangeCount = value; }
        }
    }
}
 
...from which I've extracted an interface (in IWidget.cs):
namespace PolicyInjection1
{
    public interface IWidget
    {
        int FlangeCount { get; set; }

        int GetFlangeCount();

        void SetFlangeCount(int count);
    }
}

The LogEntry is there partly to confirm that logging is correctly configured and partly to show how it interrelates to the output from the policy injection.

Here's the Program.cs file:

using System;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Unity;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace PolicyInjection1
{
    class Program
    {
        private static UnityContainer container;
        
        static void Main(string[] args)
        {
            Program.container = new UnityContainer();
            container.AddNewExtension<EnterpriseLibraryCoreExtension>();
            container.AddNewExtension<Interception>();

            UnityConfigurationSection config =
                ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
            config.Configure(container);

            IWidget widget = Program.container.Resolve<IWidget>();

            Console.WriteLine("widget is a {0}", widget.GetType().ToString());
            
            Console.WriteLine("Setting flange count to 36 using 'setter'");
            widget.SetFlangeCount(36);
            Console.WriteLine("Flange count (using 'getter') after construction = {0}", widget.GetFlangeCount());
            
            Console.WriteLine("Setting flange count to 96 using property");
            widget.FlangeCount = 96;
            Console.WriteLine("Flange count (using property) after construction = {0}", widget.FlangeCount);
            
            Console.WriteLine("Press a key to continue...");
            Console.ReadKey(true);
        }
    }
}

 It creates and configures the container, resolves and IWidget through the container, and exercises the properties and methods.


Oct 27, 2010 at 7:04 AM

And here's the App.config file, generated using the Edit Enterprise Library V5 Configuration option from VS (without Policy Injection, to confirm that everything works.  It does):

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

<configuration>
  <configSections>
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
    <listeners>
      <add name="Event Log Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        source="Enterprise Library Logging" formatter="Text Formatter"
        log="" machineName="." traceOutputOptions="None" />
      <add name="Database Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.Database.FormattedDatabaseTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Database.Configuration.FormattedDatabaseTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        databaseInstanceName="LoggingDbConnString" writeLogStoredProcName="WriteLog"
        addCategoryStoredProcName="AddCategory" formatter="Text Formatter" />
    </listeners>
    <formatters>
      <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        template="Timestamp: {timestamp(local)}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}"
        name="Text Formatter" />
    </formatters>
    <categorySources>
      <add switchValue="All" name="General">
        <listeners>
          <add name="Event Log Listener" />
          <add name="Database Trace Listener" />
        </listeners>
      </add>
    </categorySources>
    <specialSources>
      <allEvents switchValue="All" name="All Events" />
      <notProcessed switchValue="All" name="Unprocessed Category">
        <listeners>
          <add name="Event Log Listener" />
        </listeners>
      </notProcessed>
      <errors switchValue="All" name="Logging Errors &amp; Warnings">
        <listeners>
          <add name="Event Log Listener" />
        </listeners>
      </errors>
    </specialSources>
  </loggingConfiguration>
  <dataConfiguration defaultDatabase="LoggingDbConnString" />
  <connectionStrings>
    <add name="LoggingDbConnString" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Logging;Integrated Security=SSPI;"
      providerName="System.Data.SqlClient" />
  </connectionStrings>
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">

    <alias alias="Widget" type="PolicyInjection1.Widget, PolicyInjection1"/>
    <alias alias="IWidget" type="PolicyInjection1.IWidget, PolicyInjection1"/>

    <container>
      <register type="IWidget" mapTo="Widget">
      </register>
    </container>

  </unity>
  
</configuration>

And when I run it, I get the results I expect: an entry in the event log and another in the database.  So, then I add my policy injection policy and I add a couple of lines to the register tags of the IWidget, plus the extension tag:

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

<configuration>
  <configSections>
    <section name="policyInjection" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Configuration.PolicyInjectionSettings, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <policyInjection>
    <policies>
      <add name="WidgetPolicy">
        <matchingRules>
          <add type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.NamespaceMatchingRule, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            name="Namespace Matching Rule">
            <matches>
              <add match="PolicyInjection1" />
            </matches>
          </add>
        </matchingRules>
        <handlers>
          <add type="Microsoft.Practices.EnterpriseLibrary.Logging.PolicyInjection.LogCallHandler, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            beforeMessage="This is the before message" afterMessage="This is the after message"
            eventId="402" name="Logging Call Handler">
            <categories>
              <add name="General" />
            </categories>
          </add>
        </handlers>
      </add>
    </policies>
  </policyInjection>
  <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
    <listeners>
      <add name="Event Log Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        source="Enterprise Library Logging" formatter="Text Formatter"
        log="" machineName="." traceOutputOptions="None" />
      <add name="Database Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.Database.FormattedDatabaseTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Database.Configuration.FormattedDatabaseTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        databaseInstanceName="LoggingDbConnString" writeLogStoredProcName="WriteLog"
        addCategoryStoredProcName="AddCategory" formatter="Text Formatter" />
    </listeners>
    <formatters>
      <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        template="Timestamp: {timestamp(local)}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}"
        name="Text Formatter" />
    </formatters>
    <categorySources>
      <add switchValue="All" name="General">
        <listeners>
          <add name="Event Log Listener" />
          <add name="Database Trace Listener" />
        </listeners>
      </add>
    </categorySources>
    <specialSources>
      <allEvents switchValue="All" name="All Events" />
      <notProcessed switchValue="All" name="Unprocessed Category">
        <listeners>
          <add name="Event Log Listener" />
        </listeners>
      </notProcessed>
      <errors switchValue="All" name="Logging Errors &amp; Warnings">
        <listeners>
          <add name="Event Log Listener" />
        </listeners>
      </errors>
    </specialSources>
  </loggingConfiguration>
  <dataConfiguration defaultDatabase="LoggingDbConnString" />
  <connectionStrings>
    <add name="LoggingDbConnString" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Logging;Integrated Security=SSPI;"
      providerName="System.Data.SqlClient" />
  </connectionStrings>
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">

    <alias alias="Widget" type="PolicyInjection1.Widget, PolicyInjection1"/>
    <alias alias="IWidget" type="PolicyInjection1.IWidget, PolicyInjection1"/>

    <container>
      <extension type="Interception"/>
      
      <register type="IWidget" mapTo="Widget">
        <interceptor type="InterfaceInterceptor" />
        <policyInjection />
      </register>
    </container>

  </unity>
  
</configuration>

and when I run it I get a ConfigurationErrorsException, "Unrecognized element 'interceptor' (C:\Users\[...] line 85)". 

Oct 27, 2010 at 7:37 AM

Did you add reference to Microsoft.Practices.Unity.Interception.Configuration assembly?

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Oct 27, 2010 at 10:35 AM

Good morning.  Yes, I did.

Oct 27, 2010 at 10:58 AM

Cracked it!  It appears that you need:

    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />

in the unity section, even if you've got:

container.AddNewExtension<Interception>();

in the code.  My reading of the Configuring a Container for Interception document (section Adding the Interception Extension to the Container) was that they did the same thing. 

Sorry for wasting your time.

Oct 27, 2010 at 11:28 PM

Guess I also need to ask that next time someone encounters the same error.  Glad you got it working.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Oct 28, 2010 at 2:21 AM

By the way, I was able to convert the code from the MSDN article which I posted previously and verified that it works.  Actually, I only removed the usage of PolicyInjectorFactory since it no longer exists in the latest version. 

I replaced this code :

injector = fac.Create();

to

injector = new PolicyInjector(ConfigurationSourceFactory.Create());

This approach didn't involve Unity.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com