0

I would like to log to file every WCF parameters. I use parameter inspector and create recursive code for inspecting every property in every class in all inputs (my code is similar to: How to recursively print the values of an object's properties using reflection) so I can log in file like:

MethodName(string="aaa", ComplexClass=[prop="aaa", prop2="bbb"])

Unfortunately I have to change my code to do not log properties which are marked with custom attribute called NoLog. I modified my code to get attributes of every property but because every time I'm inspect parameters my code really slow down.

So my question is: how can I provide caching?

Community
  • 1
  • 1
Piotr Stapp
  • 19,392
  • 11
  • 68
  • 116

1 Answers1

4

There are some classes:

public class A
{
    public int Id { get; set; }
    public B BValue { get; set; }

    public A()
    {
        this.Id = 1000;
        this.BValue = new B();
    }
}

public class B
{
    public string Name { get; set; }
    public C CValue { get; set; }
    [NoLog]
    public string Secret { get; set; }

    public B()
    {
        this.Name = "Empty Name";
        this.CValue = new C();
    }
}

public class C
{
    public string Description { get; set; }

    public C()
    {
        this.Description = "Empty Description";           
    }
}

and NoLog custom attribue:

public class NoLogAttribute : Attribute
{

}

According to your question you use sth like this to pretty print:

public static void PrintProperties(object obj, int indent = 4, char intendCharacter = ' ')
    {
        if (obj == null) return;
        string indentString = new string(intendCharacter, indent);
        Type objType = obj.GetType();
        foreach (var pName in GetPropertiesToLogWithCaching(obj))
        {
            var property = objType.GetProperty(pName);
            object propValue = property.GetValue(obj, null);
            if (property.PropertyType.Assembly == objType.Assembly)
            {
                Console.WriteLine("{0}{1}:", indentString, property.Name);
                PrintProperties(propValue, indent + 2);
            }
            else
            {
                Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
            }
        }            
    }

I changed the way how we access properties (by name) and added for this two methods:

public static List<string> GetPropertiesToLogWithCaching(object obj)
    {
        List<string> propertiesToLog = new List<string>();
        if (obj != null)
        {
            string key = obj.GetType().FullName;
            propertiesToLog = CacheLayer.Get<List<string>>(key);
            if (propertiesToLog == null)
            {
                propertiesToLog = GetPropertiesToLog(obj);
                CacheLayer.Add<List<string>>(propertiesToLog, key);
            }
        }
        return propertiesToLog;
    }

    public static List<string> GetPropertiesToLog(object obj)
    {
        List<string> propertiesToLog = new List<string>();
        if (obj != null)
        {
            foreach (var p in obj.GetType().GetProperties().Where(prop => !Attribute.IsDefined(prop, typeof(NoLogAttribute))))
            {                   
                propertiesToLog.Add(p.Name);
            }
        }
        return propertiesToLog;
    }

where GetPropertiesToLogWithCaching is wrapper of GetPropertiesToLog. ChacheLayer object you can find here http://www.deanhume.com/home/blogpost/object-caching----net-4/37

Now it is recursive and it has caching. As I wrote in first version of answer. The idea is to chache list of properties names and than GetProperty by name without testing attributes as a key for cache we can use FullName of obj Type. Now you need to check how it works.

Łukasz Adamus
  • 266
  • 5
  • 19