Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Policy Injection Application Block – ObjectBuilder – Dependency Injection

Policy Injection Application Block – ObjectBuilder – Dependency Injection

by David Hayden, Filed: Enterprise Library 3.0

 

As I mentioned earlier, the February 2007 CTP of Enterprise Library 3.0 was released on Feb 28 and it introduces a new application block, the Policy Injection Application Block ( PIAB ).

As I understand it, the Policy Injection Application Block introduces AOP-like functionality into your winform and web applications by intercepting normal method calls and running handlers before and after method execution as defined by you through configuration. It does this by handing you a proxy class during factory creation that represents the class you asked for:

 

IOrder order = PolicyInjection.Create<Order, IOrder>();

 

If there are policies defined in the configuration file that specify certain methods be intercepted on the Order Class, the statement above will return a proxy class that does method interception, otherwise it returns an instance of the Order Class.

The policy configuration information can be located in any configuration file and looks like this:

 

<policyInjection>
    <policies>
        <add name="Policy1">
            <matchingRules>
                <add name="MatchingRule1" ... />
                <add name="MatchingRule2" ... />
            </matchingRules>
            <handlers>
                <add name="Handler1" ... />
                <add name="Handler2" ... />
            </handlers>
        </add>
    </policies>
</policyInjection>

 

Matching Rules tell the Policy Injection Application Block what methods to intercept and the handlers specify what happens before and / or after interception.

 

Example

Let's say we have a policy for our store that whenever an order is returned it must be logged along with the reason it was returned. For simplification, here are my classes:

 

public class Order : IOrder
{
    public void Return(string reason)
    {
        // Do something...
    }
}

public interface IOrder
{
    void Return(string reason);
}

 

One option is to use the Enterprise Library Logging Application Block directly and somewhere during the Return Process just make a call that logs the information:

 

LogEntry logEntry = new LogEntry();
logEntry.Message = "..."
logEntry.Categories.Add("...");

// ...

Logger.Write(logEntry);

 

With the Policy Injection Application Block, however, we can avoid this extra code by defining a policy that whenever a call is made to the Return Method on IOrder we should log a message.

There are numerous ways to match policies to methods, but in this case I am going to use the TagMatchingRule which means I just have to add a tag attribute to the Return Method on the Interface. Hence rather than writing all the LogEntry code above and explicitly calling the logging application block, I will just add the following to the IOrder Interface:

 

public interface IOrder
{
    [Tag("Log")]
    void Return(string reason);
}

 

I then define a Policy in my configuration file that says whenever [Tag("Log")] is on a method in my application ( as defined via my IOrder interface ), intercept the call and log information to the logging provider defined by the Logging Application Block:

 

<policyInjection>
    <policies>
        <add name="Logging">
            <matchingRules>
                <add type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.TagAttributeMatchingRule,
Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=2.9.9.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
"
name="Tag Matching Rule" match="Log" ignoreCase="true" /> </matchingRules> <handlers> <add name="Logging Handler" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers.LogCallHandler,
Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers, Version=2.9.9.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
"
logBehavior="Before" beforeMessage="Before" includeParameterValues="true" includeCallTime="true" includeCallStack="false" severity="Information"> <categories> <add name="General" /> </categories> </add> </handlers> </add> </policies> </policyInjection>

 

There is a decent amount of configuration in there, but you won't normally have to look at it because you will be using the Graphical Configuration Tool that is integrated into Visual Studio for managing your Enterprise Library configurations.

 

So when the following happens in my application:

 

IOrder order = PolicyInjection.Create<Order, IOrder>();
order.Return("No change in size.");

 

The Policy Injection Application Block substitutes a proxy class for my Order Class because a policy is defined on the IOrder Interface: [Tag("Log")].

When the Return Method is called, the proxy class intercepts the call and runs the handlers in the order as defined in my configuration before and after calling the Return Method associated with the Order Class. In this case, it runs the LogCallHandler which logs information in the EventLog as I defined in the Logging Application Block Section ( but didn't show here for brevity ).  What ends up in my EventLog is similar to the following but would realistically provide more useful information and be logged somewhere else:

 

Timestamp: 3/5/2007 9:12:17 PM
Message: Before
Category: General
Priority: 0
EventId: 1
Severity: Information
Extended Properties: reason - No change in size.

 

 Again, the code to do this logging is defined in policy and matched by an attribute. Here is all the code:

 

 

namespace LogMe
{
    class Program
    {
        static void Main(string[] args)
        {
            IOrder order = PolicyInjection.Create<Order, IOrder>();
            order.Return("No change in size.");
        }
    }

    public class Order : IOrder
    {
        public void Return(string reason)
        {
            // Do something...
        }
    }

    public interface IOrder
    {
        [Tag("Log")]
        void Return(string reason);
    }
}

 

A restriction worth mentioning is that in order for a method to be intercepted, the class in question must either inherit from MarshalByRefObject or implement an Interface

As you can see, the Policy Injection Application Block is definitely cool and a nice addition to the Application Blocks.

 

But Where's My Dependency Injection?

I love the new block, but have a bit of a concern. One of my concerns about the code above is this statement:

 

IOrder order = PolicyInjection.Create<Order, IOrder>();

 

Notice that I have to specify the concrete name of the class as well as the interface it implements. I would like to have a Create Method like this:

 

IOrder order = PolicyInjection.Create<IOrder>();

 

and via some Dependency Injection Container or better yet, Dependency Injection Application Block ( DIAB ), the Policy Injection Application Block just locate the concrete class ( or service really ) that goes with the interface.

I mentioned this disappointment about no DI Container for use with ObjectBuilder in another post:

 ObjectBuilder Dependency Injection Framework – Poor Undocumented Little Soul :)

 So now as I mentioned in this CodePlex Discussion in the Enterprise Library Forums:

 http://www.codeplex.com/entlib/Thread/View.aspx?ThreadId=7807

I have to use a Dependency Injection Tool alongside the Policy Injection Application Block even though ObjectBuilder plays a huge role in Enterprise Library.

And, of course, most of the software factories, like the Web Client Software Factory that I have been giving presentations on at various Florida Code Camps, use their own containers, too, so I have to coordinate them with the PIAB.

I am hoping if I keep harping on this I will either get what I want or somebody will educate me why Enterprise Library ( or Object Builder ) doesn't come with a Dependency Injection Application Block so all the applications that use Enterprise Library ( including ones built with the software factories ) don't have to use their own version.

The Policy Injection Application Block could then hook into the Dependency Injection Application Block and give us wonderful capabilities.

Conclusion

Putting the Dependency Injection aside, I really love the possibilities of the new Policy Injection Application Block. The Patterns and Practices Team is doing one helluva job on Enterprise Library and all the Software Factories.

Kudos to Tom Hollander, the Project Manager for Enterprise Library. He is very visible and proactive about providing information about what is happening with Enterprise Library in both the forums and his blog.

by David Hayden, Filed: Enterprise Library 3.0

 

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

12 Responses to Policy Injection Application Block – ObjectBuilder – Dependency Injection

  1. dhayden says:

    Ed,

    I love the Wrap<>() functionality and that is what I was using along with Windsor when trying the combination. I think decoupling responsibilities is a great idea and you have provided the ability to do DI and Policy Injection separate, but…

    We definitely need to do it together, too :)

    Unless I am totally misreading all the blog posts, forum messages, and developer conversations, the community is sorely missing a standalone container for Dependency Injection using ObjectBuilder ( call it the Dependency Injection Application Block ).

    In addition, the Policy Injection Application Block NEEDS to have seemless optional integration with this new Dependency Injection Application Block so that I can ask for a service without specifying the concrete class.

    If you want to provide an API so that other DI Tools can provide services to the PIAB, fantastic! However, I don’t want to have to use Windsor. I want it to be an option.

    I think everyone and their brothers wants something in EntLib 3.0 based on ObjectBuilder to help with DI and integrate with the PIAB.

    Can you guys deliver it?

    Regards,

    Dave

  2. DI + Policy injection are both cool, separate and together.
    The approach here is to use OB as your builder with a policy injection strategy at the end doing Wrap<>() calls on the outgoing object. One of the reasons we decoupled these 2 things is so that you can use PI in whatever other builder you have, or use Aspect# or other similar mechanism in the context of object builder (or none, for that matter).
    In our software factories (Smart Client, Web Client, etc) we are using ObjectBuilder as the factory for your business logic objects. This allows you to plug in things like Aspect# or PIAB or … into them as well, without affecting the rest too much.
    One thing we haven’t done is to wrap an easy to use facade over ObjectBuilder so it’s nice and easy to use as a standalone app container, with default strategies like PI.

    And if someone does a customization of PIAB to use the windsor proxying mechanism, please let us know how it goes on codeplex, as variability in the interception approach is something we want to support well; and I always hear good things about the windsor proxies.

  3. dhayden says:

    Leonid,

    You can download the source code at:

    http://davidhayden.com/davidhayden/downloads.aspx

    It should work fine with Feb 2007 CTP.

    Regards,

    Dave

  4. hammett says:

    Worth mention that with Windsor you can chain interceptors, and that what usually happens. You can have a logging interceptor, a transaction management interceptor and a whatnot interceptor. Each of them working side by side. And we dont have a restriction upon MarshalByRef, however, for concrete classes (no interfaces) we require the use of virtual for the methods you want to intercept.

  5. Leonid Shirmanov says:

    David –

    I tried a sample you provided in this post and run into a configuration exception from PIAB – it didn’t understand tag in Logging Handler.

    I tried without this tag in config and the handler logged an entry correctly – I guess because Special Sources were configured in Logging AB.

    Does it mean that is not supported yet in Feb CTP?

    Thanks.

  6. David,
    Yes, it has all of those capabilities.
    You can use it either via Aspect# (not really recommended, it is not under active development anymore) or by specifying interceptors for you components.
    Windsor will automatically generate a proxy for you and will send the call to your interceptor.
    I’ll post about it shortly.

  7. dhayden says:

    @Rob,

    I have some customers that either use Enterprise Library, don’t like OSS, and/or don’t like to release anything into production designated as Release Candidate.

    Enterprise Library isn’t that scary, however. I enjoy using it and the EntLib 3.0 package has a lot of nice improvements.

    @Ayende,

    I have only used Windsor for Dependency Injection. Are you saying it has AOP-like functionality as well? I noticed the Aspect# facilities in the Castle Project but haven’t looked at it. Does it have the capabilities of the PIAB?

    I know Monorail is next on my list of things to learn now that I know the Web Client Software Factory.

  8. dhayden says:

    Scott,

    I give P&P props, because I think Enterprise Library and the Software Factories are great tools as a whole that help developers be more productive as well as implement proven practices. P&P has really become more attuned to developer challenges and delivering tools to help developers with those challenges. They are also more visible and proactive about getting information and examples into our hands earlier as well as responding and acting on feedback. All of this in my mind deserves big kudos.

    The Policy Injection Application Block is not complete in the Feb 2007 CTP. It won’t be complete for another month when EntLib 3.0 is released. I expect big changes and a few wonderful surprises in its final release.

    My only concern thus far is the Dependency Injection piece which I think would make a fantastic addition for use with the Policy Injection Application Block. They may be working on it or taking my idea into consideration as we speak. I hope they are, because I think it will help Enterprise Library and the current Software Factories as a whole.

  9. David,
    you mention that you are using Windsor + the PolicyInjection block.
    Is there a reason for this?
    Windsor already has very strong support for this type of things.

  10. I agree with Scott. Also, why not just use Castle? It has everything you are looking for; plus it is more full featured and has a better implementation than what MS is releasing. The stuff Castle does excites me; the P&P stuff scares me a little…

  11. I don’t get it… you seem to be giving P&P props for a tool that you suggest isn’t complete…

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>