Mehfuz's WebLog

Live crazy, think different!

Sponsors

News

Passionate about cutting edge technologies and facinated by the modern web and phone revolution.Currently working at Telerik Corporation, the leading .net component vendor.
Follow me


Articles


Projects

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
Posted: Nov 25 2007, 10:56 PM by mehfuzh | with 7 comment(s) |
Filed under:

Comments

Gernot said:

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.  

# November 27, 2007 4:31 AM

mehfuzh said:

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 :-)

# November 30, 2007 10:33 PM

Shafqat Ahmed said:

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.

# December 7, 2007 10:11 AM

mehfuzh said:

Good catch, although the lock is not for the private  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!

# December 7, 2007 12:32 PM