More ways to inject policies
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.
Comments
Anonymous
March 06, 2007
I read my usual blogs this morning and found that it had be an unusually quiet night, you see I liveAnonymous
March 06, 2007
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? GaelAnonymous
March 07, 2007
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?Anonymous
March 07, 2007
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:
- [ApplyNoPolicies] on any types in the inheritance hierarchy => no further checks are done, no policies are applied
- [ApplyNoPolicies] on the member in the inheritance hierarchy => no further checks are done, no policies are applied
- Handlers specified in attributes on the type (anywhere in the inheritance hierarchy). Order of individual handlers cannot be guaranteed.
- 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.
- 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.
Anonymous
March 07, 2007
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.Anonymous
March 08, 2007
This seems like a cool feature, but what if i want to override this feature with configuration. Will that be possible?Anonymous
March 08, 2007
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.Anonymous
March 08, 2007
The comment has been removedAnonymous
March 10, 2007
The comment has been removedAnonymous
March 12, 2007
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? :PAnonymous
March 19, 2007
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() { }