November 2007 - Posts
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.
Recently, I did couple of posts regarding how to create a custom LINQ provider, I even created a project at Codeplex named LINQ.Flickr, that makes querying , adding and deleting photos , overall creating Flickr app much more enjoyable , with query flavor, similar to LINQ to SQL.
So , I tried to sum it all up in a article named LINQ provider Basics. Those who want to see how it is going, I definitely suggest to have a look.
Although , there is a simple web app implemented with my LINQ provider that can be downloaded from LINQ.Flickr project. But in coming posts , I will definitely try to write how to make one easily with the provider.
Thanks,
When creating custom LINQ provider , despite of looping query items, it is sometimes needed that we need to get the first , last, single or more specific items from the query result.
LINQ runtime creates Queryable instance of the query expression.Although, Queryable has a Single method defined , there is no such member in either IQueryable / IQueryProvider. Therefore, for the following query like
var query = from ph in context.Photos
where ph.Id == PhotoId
select ph;
Photo photo = query.Single<Photo>();
We need to have a mechanism, that forwards the call to our custom defined Single method.
To easily , implement that , in LINQ.Flickr provider, I have created an Custom interface called IPhotoList ,that looks like
public interface IPhotoList<T>
{
...........
T Single();
T First();
T Last();
............
...........
}
This interface is implemented in FlickrQuery, which also implementes IQueryable interface.
Now as for
Photo photo = query.Single<Photo>();
This method in FlickrQuery is called by system.
public object Execute(System.Linq.Expressions.Expression expression)
Therefore, the concept here, we will check if the expression is MethodCallExpression, if so , then we will further check if the return type is the one we are looking for , in this case Photo. Finally, we will need to reflect the method of the current class and compare that with the method for which the Execute is invoked, if both match, then we need to invoke the local equivalent for that and return the value back.
Code for that
MethodCallExpression mCallExp = (MethodCallExpression)expression;
// when first , last or single is called
if (mCallExp.Method.ReturnType == typeof(Photo))
{
Type itemType = this.GetType();
string methodName = mCallExp.Method.Name;
MethodInfo[] mInfos = itemType.GetMethods();
foreach (MethodInfo mInfo in mInfos)
{
if (string.Compare(methodName, mInfo.Name, false) == 0)
{
return itemType.InvokeMember(methodName, BindingFlags.InvokeMethod, null, this, null);
}
}
}
Hope this is useful,
More Posts