Examine content of IMethodReturn for auditing AOP

Mar 19, 2012 at 5:44 PM

I have implemented a container on an interface to our repository. I have configured the container with interception and injected a class in the chain that inherits IInterceptionBehavior. This all works as expected.

The intercepted methods all return complex objects with a custom attribute on the properties that require an entry in an audit repository. (See objects below).

What I need to do is extract each property and the content of it as well as the properties on the base class that also have the attribute. Each property needs to be checked for the presence of an attribute modifier to suppress the audit when appropriate.

Any guidance on how to approach this via access to the object contained within the IMethodReturn.ReturnValue will be appreciated.

This is part of one possible method response object

   [DataContract]
   public class GetResponseBase
   {
        [DataMember(Name = "TotalQueryRows")]
        public int TotalQueryRows { get; set; }
   }

       [DataContract]
       public class GetCompanyResponse : GetResponseBase
       {
              [DataMember(Name = "CompanyList")]
              public IEnumerable<Company> CompanyList { get; set; }
       }

 This is part of the object contained in the List of objects returned by the method

   [DataContract]
   public class DataEntityBase
   {
       [DataMember]
       [XmlElement("UserAccessing")]
       [ScaffoldColumn(false)]
       [AuditThis]
       public int UserAccessing { get; set; }
   }

       [DataContract]
       public partial class Company : DataEntityBase
       {
              [DataMember]
              [AuditThis(SuppressAudit = true )]
              public Int32? CompanyCode { get; set; }
              [DataMember]
              public string CompanyName { get; set; }
       }
 

This is the audit attribute declaration for selected properties. The default is to audit everything and the Boolean on each property allows for conscious suppression of an audit to suppress ‘noise’ when appropriate.

   [AttributeUsage(AttributeTargets.All)]
   public class AuditThis: Attribute

   {
       public bool SuppressAudit{get;set;}
       public string PropertyNameOverride { get; set; }

   }

Mar 20, 2012 at 5:07 AM

You should be able to do this.  I think you are talking about doing something like the following:

IMethodReturn ICallHandler.Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
    IMethodReturn result = getNext()(input, getNext);

    foreach (var property in result.ReturnValue.GetType().GetProperties())
    {
        var auditAttribute = property.GetCustomAttributes(typeof(AuditThis), true);

        if (auditAttribute != null && auditAttribute.Count() == 1)
        {
            if (((AuditThis)auditAttribute[0]).SuppressAudit)
            {
                Console.WriteLine("Supressing Audit for property " + property.Name);
            }
            else
            {
                Console.WriteLine("Auditing property " + property.Name + ".   The value is " + 
                    property.GetValue(result.ReturnValue, null) ?? "");                        
            }
        }
        else
        {
            Console.WriteLine("No Audit Attribute for property " + property.Name);
        }
    }

    return result;
}

The above example uses is based on a CallHandler but should be virtually the same for IInterceptionBehavior. 

The inheritance tree is already checked but you will have to account for the return object containing other objects that must also be checked for the Audit attribute or if there are properties that have indexers etc.  

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Mar 20, 2012 at 9:27 PM

Randy,

Thanks so much for the quick response.

I was able to use your example to make some progress.

The issue I am having is to get deeper into the ReturnValue. It appears that IMethodReturn always has three properties (“Capacity”[Int32], “Count”[Int32], and “Item”[MyObject]).

‘Item’ has the complex object I need to extract the content from. It is not clear to me if I can get the values from the properties within the objects contained in the 'Item' property of the IMethodReturn. I am currently digging into the properties of the 'properties to see if thre is a way to discriminate the complex objects from the simple one without too much code. IsPrimitive  does not work universally since Int32 return true but a nullable Int32 returns false. Anyway, hopefullyI can get the desired behavior. I'll follow up with progress.

Thanks again

Mar 20, 2012 at 11:00 PM

IMethodReturn returns four properties: Exception, InvocationContext, Outputs, and ReturnValue.

The ReturnValue is what you are interested in (I think) and it will be whatever type the object the method is returning is.  I think you will have to walk the object graph to extract all potential properties that can be audited.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Mar 21, 2012 at 12:42 AM

Randy,

I misspoke. When I said IMethodReturn, I meant the ReturnValue property of IMethodReturn, which has the three properties I referred to.

Processing the tree is not the proble. That should be able to be done recursively. The issues I am having with the object graph is that, as I indicated, it does not appear trivial to identify a basic property in the graph from which to extract tyhe value for auditing. Things like IsPrimitive do not yield the same result when a reference type like Int32 is not the seen as the same as a nullable Int32. So, is there any uncomplicated way to identify the 'primitive' properties in the object graph, or do I need to do a lot of type interrogation in traversing the graph?

Thanks again for your help. It has saved me time and I appreciate it.