Tom Hollander's blog

patterns, practices and pontification

More ways to inject policies

More ways to inject policies

  • Comments 11

I wanted to quickly fill you in on a couple of new additions we've made to the Policy Injection Application Block since last week's CTP that will give you more control over which objects and members your policies are applied to.

In the CTP, the only way of applying policies to members is via Matching Rules. A matching rule encapsulates logic that determines if a member should have a policy applied to it. Matching rules included with the block include ones that check for assembly, namespace, type name and signature. We also include one that looks for members with the TagAttribute applied with a particular value, eg:

        [Tag("ValidateMe")]

        public void Deposit([RangeValidator(typeof(Decimal), "0.0", RangeBoundaryType.Exclusive, "0.0", RangeBoundaryType.Ignore)] decimal depositAmount)

        {

            balance += depositAmount;

        }

This matching rule is useful as it allows you to be very precise about exactly which members you want to apply certain policies to. However in some situations you may know exactly which handlers you want applied, and using external policies may not be desirable as it can obfuscate the behavior and allow post-deployment changes that you may not want. To deal with these situations, we've added support for specifying specific handlers using attributes. These attributes can be applied to members or types as follows:

        [ValidationCallHandler]

        public void Deposit([RangeValidator(typeof(Decimal), "0.0", RangeBoundaryType.Exclusive, "0.0", RangeBoundaryType.Ignore)] decimal depositAmount)

        {

            balance += depositAmount;

        }

In this example, you don't need to define a policy in configuration at all. Provided the object was created or wrapped using the PolicyInjection class, any call to this method will have the Validation call handler injected between the client and the object. You could also apply multiple handlers on a type or method by specifying multiple attributes.

The other relevant post-CTP change we made in this area was the addition of the ApplyNoPoliciesAttribute. (I lobbied unsuccessfully to call this the Dont%$&#WithMeAttribute, or the CLS-compliant variation of the same). As both variants of the name suggest, applying this attribute to a type of member will indicate that you don't wany any policies or handlers applied, even if the matching rules or handler attributes would normally result in handlers being attached. This attribute can be useful in situations where any PIAB-provided surprises could adversely affect functionality or performance.

Hopefully these changes will give you the necessary flexibility in using either a broad or a fine brush to specify which cross-cutting concerns you want to apply to which objects in your applications.

  • I read my usual blogs this morning and found that it had be an unusually quiet night, you see I live

  • Tom,

    Excellent. This will certainly be useful in some scenarios. And I will update my PostSharp4EntLib of course :-).

    A question: how do you cope with priority of handlers? What if many policies and/or many handlers are applied to a method. Handlers are not "commutative", so in which order should they be executed?

    Gael

  • Ah - what if I want even _more_ post-deployment changes? While the TagAttribute gives a little bit of flexibility, I'd really like to be able to change PolicySets at runtime. At the moment, it seems the only way to do this is to change my IConfigurationSource every time. Any plans along those lines?

  • Gael: the precedence logic is as follows.

    Searches are done in the following order, with handlers discovered later in the process being applied closer to the target:

    1. [ApplyNoPolicies] on any types in the inheritance hierarchy => no further checks are done, no policies are applied

    2. [ApplyNoPolicies] on the member in the inheritance hierarchy => no further checks are done, no policies are applied

    3. Handlers specified in attributes on the type (anywhere in the inheritance hierarchy). Order of individual handlers cannot be guaranteed.

    4. Handlers specified in attributes on the member (anywhere in the inheritance hierarchy). Handlers specified on property getters/setters are placed closer to the target than handlers specified on the overall property. In any case, order of individual handlers specified on the same element cannot be guaranteed.

    5. Matching policies specified in configuration. Policies configured later in the file will be applied closer to the target. Handlers within each policy will be applied in the order specified, further down means closer to the target.

  • Thom,

    If you want to switch policy sets at runtime, you'll need to skip the PolicyInjection facade and use the underlying PolicyInjector class directly. Each PolicyInjector can be created with its own PolicySet; which injector you use determines which policies get applied.

  • This seems like a cool feature, but what if i want to override this feature with configuration. Will that be possible?

  • Benny: you can always add new policies through configuration, but you can't remove any defined through code. The reasoning is that you wouldn't attach handlers via attributes unless you're sure you always want them.

  • Chris - I'm afraid that went over my head, I'm not sure what you mean by a PolicyInjector class. I see now that I can create an InterceptingRealProxy with a PolicySet that gets applied to the proxy - is that what you mean?

    Given that, I could easily create my own factory that allows clients to change the current policy set, but it just feels like this should be a method on the PolicyInjection class - instead of taking a configuration and querying it for the PolicySet, just having another overload that takes it directly.

  • Thom,

    If you look at the code for the PolicyInjection class, you'll see under the hood it uses an instance of the PolicyInjector class to do the actual wiring up.

    If you want to wrap objects with different policy sets, the easiest way is to do something like this:

    PolicySet poicies = <get policies however you want>;

    PolicyInjector injector = new PolicyInjector(policies);

    Foo myObjec t= injector.Create<Foo>();

    For each policy set, create a new PolicyInjector.

    Does that help?

    -Chris

  • That does look like exactly what I want, but it doesn't match what I've got. :(

    I have Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=2.9.9.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, and the Create<T> calls all end up calling WrapObject<T> which looks like this:

    public static TInterface WrapObject<TInterface>(IConfigurationSource configurationSource, object instance)

    {

       PolicySetFactory policySetFactory = new PolicySetFactory(configurationSource);

       InterceptingRealProxy proxy = new InterceptingRealProxy(instance, typeof(TInterface), policySetFactory.Create());

       return (TInterface)proxy.GetTransparentProxy();

    }

    Is my version out of date so soon? :P

  • Orders of handlers specified by attributes can't be garanteed????

    This is really BAD. What about the security validation vs. caching handlers problem if we don't want to configure policies in config file? (Non authorizes items can't be served)

    Is this due to reflexion API? If so, It would be useful to have an "order" integer parameter in the handlers attribute. Let's say :

    [ValidationCallHandler(0)]

    [CacheHandler(1)]

    public IList GetSomeData() { }

Page 1 of 1 (11 items)