RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


How To Create a Custom Policy Injection Application Block Handler : Page 3

Using custom policy injection, you can configure and apply policies exactly the way you want—but doing it right requires a little effort.

Accessing Data in Request and Return Messages
To demonstrate how you can access the contents of the request and return invocation messages, the handler used in the example application contains extra code that displays the target object and member name, any parameters passed to the target member, and any value that the target member returns. This version of the handler is a single class located in the file NeverOnASundayCallHandler.cs (in the App Blocks\Src\PolicyInjection\CallHandlers subfolder of the Enterprise Library source code). If you are editing the existing Enterprise Library project, you must ensure that you place the class in the correct namespace (Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers), and add using statements for the other namespaces required. Open the sample project to see the complete file.

The next two code fragments show the new code added to the Invoke method in this version of the handler (the remainder of the class is the same as you saw in the previous section of this article). The first new code section obtains a reference to the current ASP.NET context so that it can write to the Trace object to display data about the target member invocation. It then accesses and displays the Target and MethodBase properties of the IMethodInvocation instance passed to the Invoke method to show the name of the target object and the name of the target member (method or property accessor).

Next, the code accesses the Inputs property of the IMethodInvocation instance, which contains a reference to an object that implements the IParameterCollection interface, and iterates through this list accessing the individual parameters passed to the target member. For each one, the code displays the parameter name and the value (or the type name if it is not a value type):

   public IMethodReturn Invoke(IMethodInvocation input, 
      GetNextHandlerDelegate getNext)
      // Display information about the method/property call.
      HttpContext context = HttpContext.Current;
      context.Trace.Warn("NOASHandler", "Target Object: " + 
      context.Trace.Warn("NOASHandler", "Target Method: " +  
      IParameterCollection targetInputs = input.Inputs;
      for (Int32 i = 0; i < targetInputs.Count; ++i)
         context.Trace.Warn("NOASHandler", "Parameter '" + 
            targetInputs.ParameterName(i) + "' = " + 
The next section of the code (not shown here) is the same as in the simple version of the handler. It calculates the current weekday, and generates the appropriate exception and return message if it is a day when invocation is not permitted. However, if invocation is permitted, the else clause contains some extra code in this version of the handler to extract and display the return value.

To do this, the first step is to generate a return message as an implementation of the IMethodReturn interface, using the CreateMethodReturn method of the original invocation message (the IMethodInvocation implementation). The simple version of the handler used this code to invoke the next handler and then pass the return message back to the caller:

   return getNext()(input, getNext);  
However, to generate a return message directly, the code must execute the getNext delegate to invoke the next handler, and then use the return value from the getNext delegate in the CreateMethodReturn method. This method also requires the array of parameters passed to the method, available from the Arguments property of the original invocation message:

         // Invoke the next handler and create the return message using the
         // return value from the target (the next handler or the target 
         // object) and the parameters passed to the target.
         IMethodReturn returnMessage = input.CreateMethodReturn(
            getNext()(input, getNext).ReturnValue, input.Arguments);
         // Display the return value of the method/property (if any)
         Object returnValue = returnMessage.ReturnValue;
         if (returnValue != null)
            context.Trace.Warn("NOASHandler", "Return Value: " +  
         // Return the invocation return message to the caller.
         return returnMessage;
Having generated the return message, the code can display the return value from the target member (if any), and then return the message to the caller.

Creating the Handler's Configuration Class
To read configuration data, the new handler requires a matching configuration class, which you'll find in the new file NeverOnASundayCallHandlerData.cs (in the App Blocks\Src\PolicyInjection\CallHandlers\Configuration subfolder of the Enterprise Library source code). If you are editing the existing Enterprise Library project, you must ensure that you place the class in the correct namespace (Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers.Configuration), and add using statements for the other namespaces required. Open the sample project to see the complete file.

The configuration class inherits from the CallHandlerData base class, and defines the name of the configuration file attribute used in the <add> element that will add this handler to the configuration—in this case the attribute name is notSaturdayEither. The configuration class also contains two constructors:

  • A default constructor that sets the NotSaturdayEither property to the default value exposed by the field named DefaultNotSaturdayEither in the NeverOnASundayCallHandler class.
  • A constructor that takes a handler name and generates an instance of the hander with that name by calling the base class constructor. This also sets the default value for the NotSaturdayEither property.
Finally, the configuration class exposes the NotSaturdayEither property, using a ConfigurationProperty attribute to specify the attribute name that corresponds to this property:

   public class NeverOnASundayCallHandlerData : CallHandlerData
      private const string NotSaturdayPropertyName = "notSaturdayEither";
      public NeverOnASundayCallHandlerData()
         NotSaturdayEither = NeverOnASundayCallHandler.
      public NeverOnASundayCallHandlerData(string handlerName)
         : base(handlerName, typeof(NeverOnASundayCallHandler))
         NotSaturdayEither = NeverOnASundayCallHandler.
      public Boolean NotSaturdayEither
         get { return (Boolean)base[NotSaturdayPropertyName]; }
         set { base[NotSaturdayPropertyName] = value; }
Notice that the class is decorated with an [Assembler] attribute that specifies the class that Enterprise Library will use, via ObjectBuilder, to create configured instances of the handler. The next code fragment shows the NeverOnASundayCallHandlerAssembler class:

   public class NeverOnASundayCallHandlerAssembler 
     : IAssembler<ICallHandler, CallHandlerData>
      public ICallHandler Assemble(IBuilderContext context,
         CallHandlerData objectConfiguration,
         IConfigurationSource configurationSource,
         ConfigurationReflectionCache reflectionCache)
          NeverOnASundayCallHandlerData handlerConfiguration 
             = (NeverOnASundayCallHandlerData)objectConfiguration;
          return new NeverOnASundayCallHandler(
This is the generic technique for creating configuration data instances in Enterprise Library—implementing the Assemble method that takes a range of parameters. After doing that, all that remains is to cast the objectConfiguration to the required configuration type (NeverOnASundayCallHandlerData in this case) and generate a new instance of the handler class using the value of the NotSaturdayEither property from the NeverOnASundayCallHandlerData instance.

At this point the new handler will work, but only if you manually edit the application configuration. The next step is to add the design support classes and code for the handler so developers and administrators can configure it using Enterprise Library's configuration tools.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date