BloggingAbout.NET
Thoughts of developers
Policy Injection with WCF Service

The following is an example of using the Enterprise Library 3.1 Policy Injection Library.

Overview

The solution is made of a single console application that hosts a named pipe service and client.  The service implements IEchoService that will reply back to a client with a received string (hence IEchoService).

Console Program

First a console application was created as the basis of the project.  A reference to System.ServiceModel added and the following describes the console application:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Text;
   4: using System.ServiceModel;
   5:  
   6: namespace EntLibPolicyInjectionExample
   7: {
   8:     class Program
   9:     {
  10:         static void Main(string[] args)
  11:         {
  12:             // start a host to listen for requests
  13:             EchoHost theHost = new EchoHost();
  14:             theHost.StartHost();
  15:  
  16:             // create the client proxy
  17:             ChannelFactory<IEchoService> factory = new ChannelFactory<IEchoService>(
  18:                     new NetNamedPipeBinding(), new EndpointAddress(theHost.HostAddress));
  19:  
  20:             try
  21:             {
  22:                 IEchoService proxy = factory.CreateChannel();
  23:                 Console.WriteLine(proxy.Echo("This is a call that should be captured by the enterprise library"));
  24:                 Console.WriteLine(proxy.Echo("A second call."));
  25:                 ((IClientChannel)proxy).Close();
  26:             }
  27:             finally
  28:             {
  29:                 factory.Close();
  30:             }
  31:  
  32:             // stop the host
  33:             theHost.StopHost();
  34:  
  35:             Console.WriteLine();
  36:             Console.Write("Press a key to end...");
  37:             Console.Read();
  38:         }
  39:     }
  40: }

EchoService

The service contract, implementation and a simple host class were all created in the same file for simplicity.  There is nothing unusual to note here except the key is to make sure the object that is to be "policy injected" needs to be imperceptible by the enterprise library.  This requires the class to extend MarshalByRefObject and to be marked with the service behavior attribute tag: InstanceContextMode.Single.  Thankfully, the Enterprise Library authors created very clear error messages.

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Text;
   4: using System.ServiceModel;
   5: using System.Security;
   6: using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;
   7:  
   8: namespace EntLibPolicyInjectionExample
   9: {
  10:     internal class EchoHost
  11:     {
  12:         ServiceHost host = null;
  13:         const string baseAddress = "net.pipe://localhost/MyPipes";
  14:         const string endpointAddress = "EchoService";
  15:  
  16:         public string HostAddress = baseAddress + "/" + endpointAddress;
  17:  
  18:         EchoService svc = null;
  19:  
  20:         public void StartHost()
  21:         {
  22:             EchoService svc = PolicyInjection.Create<EchoService>("EchoService as NamedPipe: ");
  23:  
  24:             host = new ServiceHost(svc, new Uri(baseAddress));
  25:             host.AddServiceEndpoint(typeof(IEchoService), new NetNamedPipeBinding(), endpointAddress);
  26:             host.Open();
  27:             Console.WriteLine("Host opened.");
  28:         }
  29:  
  30:         public void StopHost()
  31:         {
  32:             host.Close();
  33:             Console.WriteLine("Host close.");
  34:         }
  35:     }
  36:  
  37:     // MarshalByRefObject and InstanceContextMode.Single are required to allow an instance of EchoService
  38:     // to be interceptable by the Enterprise Library
  39:     [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
  40:     internal class EchoService : MarshalByRefObject, IEchoService
  41:     {
  42:         string _header = string.Empty;
  43:         public EchoService(string header)
  44:         {
  45:             _header = header;
  46:         }
  47:  
  48:         public string Echo(string request)
  49:         {
  50:             return _header + request;
  51:         }
  52:     }
  53:  
  54:     [ServiceContract(Name = "IEchoService")]
  55:     internal interface IEchoService
  56:     {
  57:         [OperationContract(IsTerminating = false, IsInitiating = true, IsOneWay = false, AsyncPattern = false, Action = "EchoService")]
  58:         string Echo(string request);
  59:     }
  60: }

The PolicyInjection.Create<TObject>() step will use the configuration settings in app.config to apply any handlers to the class.  In this example, I have attached a LogCallHandler that will create a trace message at the start and end of the Echo method. 

At this stage, references to the enterprise libraries should be made:

Microsoft.Practices.EnterpriseLibrary.Logging
Microsoft.Practices.EnterpriseLibrary.PolicyInjection
Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers

Configuration

In the app.config, the policy injection configuration has two important sections: matchingRules and handlers.  In the matchingRules section, the item to apply the handlers is identified.  There are several matchingRules that can be used to determine and I have chose to match on the Type of the object and the method name being called.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <configuration>
   3:     <configSections>
   4:         <section name="policyInjection" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Configuration.PolicyInjectionSettings, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
   5:         <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />        
   6:     </configSections>
   7:     <policyInjection>
   8:         <policies>
   9:             <add name="Policy">
  10:                 <matchingRules>
  11:                     <add type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.MemberNameMatchingRule, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  12:                         name="Member Name Matching Rule">
  13:                         <matches>
  14:                             <add match="Echo" ignoreCase="false" />
  15:                         </matches>
  16:                     </add>
  17:                     <add type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.TypeMatchingRule, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  18:                         name="Type Matching Rule">
  19:                         <matches>
  20:                             <add match="EchoService" ignoreCase="false" />
  21:                         </matches>
  22:                     </add>
  23:                 </matchingRules>
  24:                 <handlers>
  25:                     <add logBehavior="BeforeAndAfter" beforeMessage="Before Echo"
  26:                         afterMessage="After Echo" eventId="52" includeParameterValues="true"
  27:                         includeCallStack="false" includeCallTime="true" priority="-1"
  28:                         severity="Information" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers.LogCallHandler, Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  29:                         name="Logging Handler">
  30:                         <categories>
  31:                             <add name="General" />
  32:                         </categories>
  33:                     </add>
  34:                 </handlers>
  35:             </add>
  36:         </policies>
  37:     </policyInjection>
  38:     <loggingConfiguration name="Logging Application Block" tracingEnabled="true"
  39:         defaultCategory="General" logWarningsWhenNoCategoriesMatch="true">
  40:         <listeners>
  41:             <add source="Enterprise Library Logging" formatter="Text Formatter"
  42:                 log="Application" machineName="" listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  43:                 traceOutputOptions="None" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  44:                 name="Formatted EventLog TraceListener" />
  45:         </listeners>
  46:         <formatters>
  47:             <add template="Timestamp: {timestamp}&#xD;&#xA;Message: {message}&#xD;&#xA;Category: {category}&#xD;&#xA;Priority: {priority}&#xD;&#xA;EventId: {eventid}&#xD;&#xA;Severity: {severity}&#xD;&#xA;Title:{title}&#xD;&#xA;Machine: {machine}&#xD;&#xA;Application Domain: {appDomain}&#xD;&#xA;Process Id: {processId}&#xD;&#xA;Process Name: {processName}&#xD;&#xA;Win32 Thread Id: {win32ThreadId}&#xD;&#xA;Thread Name: {threadName}&#xD;&#xA;Extended Properties: {dictionary({key} - {value}&#xD;&#xA;)}"
  48:                 type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  49:                 name="Text Formatter" />
  50:         </formatters>
  51:         <categorySources>
  52:             <add switchValue="All" name="General">
  53:                 <listeners>
  54:                     <add name="Formatted EventLog TraceListener" />
  55:                 </listeners>
  56:             </add>
  57:         </categorySources>
  58:         <specialSources>
  59:             <allEvents switchValue="All" name="All Events" />
  60:             <notProcessed switchValue="All" name="Unprocessed Category" />
  61:             <errors switchValue="All" name="Logging Errors &amp; Warnings">
  62:                 <listeners>
  63:                     <add name="Formatted EventLog TraceListener" />
  64:                 </listeners>
  65:             </errors>
  66:         </specialSources>
  67:     </loggingConfiguration>
  68: </configuration>

Conclusion

Given the flexibility and simplicity of the Policy Injection library, it is a great addition to the enterprise library.  In general, I have noticed a small hit in performance only on the instantiation of the object and not to subsequent method calls.  The performance hit generally speaking is measured in milliseconds so for my purposes inconsequential.

In all situations of frustration with getting the library to work, it has come down to configuration mistakes and usually to missing libraries.  So, if you are calling an object out of a dll, make sure it is in the GAC or a local reference.


Posted Mon, Nov 5 2007 12:14 PM by chilberto

Comments

Jeffrey's Blog wrote Enterprise Library Policy Injection Application Block example
on Mon, Nov 5 2007 1:42 AM

Enterprise Library Policy Injection Application Block example

Jeffrey Chilberto wrote Enterprise Library: PolicyInjection with WCF
on Mon, Nov 5 2007 1:44 AM

I have created an example using Enterprise Library&#39;s Policy Injection application block. In this

Dennis van der Stelt wrote re: Policy Injection with WCF Service
on Mon, Nov 5 2007 10:16 AM

Sweet example dude! Great work! I'll have a look at it myself some time!

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

Please add 4 and 2 and type the answer here:
Copyright © 2003-2008 BloggingAbout.NET
Powered by Community Server (Commercial Edition), by Telligent Systems