Problem with Policy Injection and Validation

Topics: Policy Injection Application Block, Validation Application Block
Mar 19, 2007 at 5:41 PM
Edited Mar 19, 2007 at 5:43 PM
I am having some problems getting the Validation block to work properly with the Policy Injection block. I know that the PIAB is relatively new so I was wondering if tag matching is supposed to work. I walked through an example and the PolicySet is properly set with the validation callhandler and my matchhandler and it seems to assign properly to a method that I have marked in my interface. However, the Invoke method for the Validation handler is never called and validation never occurs.

I think I am missing something fundamental but I can't figure out what it is. All relevant code is below - I appreciate any assistance anyone can give.

Config file
<policyInjection>
	<policies>
		<add name="Validation">
			<matchingRules>
				<add 
             type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.TagAttributeMatchingRule
                         , Microsoft.Practices.EnterpriseLibrary.PolicyInjection" 
                         name="Tag Matching Rule"  
                         match="ValidateEntity" 
                         ignoreCase="true" />
			</matchingRules>
			<handlers>
				<add name="Validation Handler" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers.ValidationCallHandler, Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers" specificationSource="Both" />
			</handlers>
		</add>
	</policies>
	</policyInjection>

The interfaces:

public interface IDao<T, K> where T : IEntity
{
  [Tag("ValidateEntity")]
  void Create(IEntity obj);
}
 
public interface IAccountDao : IDao<Account, Guid>
{
        
}
 

The concrete class:
public class AccountDao : DaoBase<Account, Guid>, IAccountDao
{
  public override void Create(IEntity obj)
  {
    using (Repository rep = new Repository()) {}
  }
}

I instantiate the DAO class:

public class DaoFactory : IDaoFactory
{
  public IAccountDao GetAccountDao()
  {
    IAccountDao adao = PolicyInjection.Create<AccountDao, IAccountDao>();
    return new AccountDao();
  }
}

The actual entity class with validation:
public class Account : EntityBase
{
       private string _name;
       [StringLengthValidator(1,100, MessageTemplate="The Name must be between 1 and 100 characters in length.")]
       public virtual string Name
       {
            get { return _name; }
            set
            {
                _name = value.Trim();
            }
       }
}

Then to test I run the following NUnit test:

[Test]
public void TestBasicCrud()
{
  Account account = new Account();
  account.Name = string.Empty;
  IAccountDao dao = new DaoFactory().GetAccountDao();
  dao.Create(account);
}
Mar 19, 2007 at 7:15 PM
I suspect you've hit a minor bug in the CTP bits. Could you do me a favor and try moving the TagAttribute to AccountDao.Create instead of having it on the interface?

It will work with the tag on the interface in the release bits, but the CTP has some issues around interfaces.

-Chris
Mar 19, 2007 at 7:17 PM
Without trying myself, I think there is a problem here-

public class DaoFactory : IDaoFactory
{
  public IAccountDao GetAccountDao()
  {
    IAccountDao adao = PolicyInjection.Create<AccountDao, IAccountDao>();
    return new AccountDao();
  }
}

I assume you want your return statement to be:

return adao;

so that you are accessing the proxy class to do validation on the Account Instance.

Regards,

Dave

_________________________

David Hayden
Microsoft MVP C#
Mar 19, 2007 at 7:37 PM
David,

Good eyes, I missed that one. Yes, without returning the proxy nothing's going to be intercepted.

However, there's probably still an issue with the tag attribute on the interface. Which has been fixed in our current tree, but not in the CTP.
Mar 19, 2007 at 8:12 PM
Now that's just slightly embarassing...thanks for the catch. To think I spent about 4 hours trying to figure out what I was doing wrong.

It now works perfectly with the interface. Chris, the reason I was working with the interface is that I could not get the match to work with the concrete class. I found that when the code entered the TagAttributeMatchingRule, it would only recognize the interface in the code below and not the conrete class. Of course, given my mistake above, it was probably something I was doing.

Thanks again for the help!

// would only recognize the custom attributes set on the interface, never on the concrete classes.
foreach (TagAttribute tagAttribute in member.GetCustomAttributes(typeof(TagAttribute), true))
{
  if (string.Compare(tagAttribute.Tag, tagToMatch, ignoreCase) == 0)
  {
     return true;
  }
}
return false;
Mar 19, 2007 at 8:47 PM
Edited Mar 19, 2007 at 8:48 PM
Actually, something for others to look out for. I could not get the validatable object to validate. It was because I was passing an interface into my DAOClass (IEntity). When I passed the concrete object itself, the validations began working properly.

All in all, other than the issues to be expected with unreleased software, I am REALLY liking the injection block. Good work!
Mar 19, 2007 at 11:50 PM
Having the attributes on the interface or on the concrete type are both supposed to work. It just took us a little while to find all the corner cases, so both will work when we release.

Thanks for the kind words about PIAB, and please keep the feedback coming!

-Chris
Mar 20, 2007 at 4:23 PM
Edited Mar 20, 2007 at 4:24 PM
In order for it to work on concrete class methods, I believe the current requirement is that the class has to inherit from MarshalRefByObject. The PIAB won't work with a class that is derived from just System.Object.

Any chance the PIAB will support interception of virtual properties/methods on a class that derives from System.Object when released to avoid the current MarshalRefByObject limitation?

Regards,

Dave

______________________

David Hayden
Microsoft MVP C#
Mar 20, 2007 at 5:44 PM
Dave - we won't be supporting this in v1, but there are various interception approaches that allow this (eg dynamically emitting a class deriving from the target class, including the calls to the pipeline). Maybe some kind person in the community will put together something along these lines :-)

Tom