How to control C# interface behavior using attribute.

Attribute based programming is the most cool thing in C#,  using attributes you can control how your target method should behave leaving the main code absolutely un-touched. Moving forward, let's say we are doing a service call and we want to define the external method  right from the interface.

Now, here is an interface

public interface IFlickr : IDisposable
{
 // photo releated method.
 [FlickrMethod("flickr.photos.getInfo")] 
 Photo GetPhotoDetail(string id, PhotoSize size);
....
....
....
}

As, you can see I have defined the REST method to be called along with method declaration.To make this happen, on the start of every interface implementation we need to add, for example, in LINQ.Flickr project , inside the DataAccess that implements IFlickr, looks like

Photo IFlickr.GetPhotoDetail(string id, PhotoSize size)
{
....
....
    string method = Helper.GetExternalMethodName();
....
....
....
}

As, we can see that the actual magic goes to a Helper class that will extract the attribute value from the interface. Basically, on each method call, the execution of the extraction code is bit costly. Therefore, the best solution is to parse the attributes for interface when DataAccess class is initialized and store it in a key value pair dictionary.

Therefore, Inside the .ctor call of DataAccess. let's add the following lines:

public DataAccess()
{
    try
    {
         .....
         .....

          Helper.RefreshExternalMethodList(typeof(IFlickr));
    }
    catch (Exception ex)
    {
        throw new ApplicationException(ex.Message);      
    }
}

Lets step in to RefreshExternalMethodList and we will get

private static IDictionary<string, string> _methodList = new Dictionary<string, string>();

internal static void RefreshExternalMethodList(Type interfaceType)
{
    // not yet initialized.
    if (_methodList.Count == 0)
    {
        MethodInfo[] mInfos = interfaceType.GetMethods();

        foreach (MethodInfo mInfo in mInfos)
        {
            if (mInfo != null)
            {
                object[] customArrtibute = mInfo.GetCustomAttributes(typeof(FlickrMethodAttribute), true);

                if (customArrtibute != null && customArrtibute.Length == 1)
                {
                    FlickrMethodAttribute mAtrribute = customArrtibute[0] as FlickrMethodAttribute;

                    string methodFullName = mInfo.ReflectedType.FullName + "." + mInfo.Name;

                    if (!_methodList.ContainsKey(methodFullName))
                    {
                        _methodList.Add(methodFullName, mAtrribute.MethodName);
                    }
                }
            }
        }

    }
}

Which does nothing but maps the Interface method to an external method. Going back to GetExternalMethodName() , it takes the interface reference from the current stacktrace and passes the name to return the name of the external method. That looks like

private static object _lockHandler = new object();

internal static string GetExternalMethodName()
{
    lock (_lockHandler)
    {
        StackTrace trace = new StackTrace(1, true);
        MethodBase methodBase = trace.GetFrames()[0].GetMethod();
        return _methodList[methodBase.Name];
    }
}

Note that StackTrace is started from 1st frame that means it gets frame list starting from last method, which is the IFlickr implementation in DataAccess class.

Did I miss anything, yep happy holidays and thanksgiving :-)

 

Update (2010) : Never use attribute unless it is aboslutely necessary. The more attributes you will use, the more your code will loose its adaptibiliy and will become hardly dependent on a particular tool / technology.

kick it on DotNetKicks.com

4 Comments

  • Sorry, but your example has nothing to do with AOP. AOP is a way to add functionality that is executed before or after method calls. If you know rails, before_filter and after_filter is AOP.

  • Yes, you are right about AOP, the example is basically way of attribute base programming sample, i have removed the "AOP" word from the top of my article.

    Any suggestions are most welcome :-)

  • Nice post. Don't think you that you need to do a "lock (_lockHandler)" when you try to get the parent method name. On a multithreaded environment it may cause wait time becuase of locks. Since the stacktrace is a private variable with method scope only, you will not need to make it explicitly threadsafe ... it is thread safe by default.

  • Good catch,&nbsp;although the lock&nbsp;is not for the private &nbsp;StackPanel , it is for shared static variable "_methodList[methodBase.Name]", but as it is readonly, lock is not needed at all , anyway.
    Thanks for the comment!

Comments have been disabled for this content.