ASpeak IOpine!

First encounter with OData

Posted on May 3, 2010

After installing VS2010 Professional I could not resist my temptation to start spelunking the newer features available to me. I have seen a couple of videos about OData in Mix10 and I thought it would be the easiest to begin with. I didn’t know the very first encounter with creature of this type would demystify a bug in it. I opened up my solution which comprises of various test projects. I added a new Console Application Project targeting the DotNET4ClientFramework. I added reference to the Mix10Live OData Feed and followed as was demonstrated by presenters in the mix video.

Following is the code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ODataTest.Mix10Live;
 
namespace ODataTest
{
    class Program
    {
        static void Main(string[] args)
        {
            EventEntities eventEntities = new EventEntities(new Uri("http://api.visitmix.com/OData.svc"));
            try
            {
                var query = eventEntities.Speakers.Where(x => x.Sessions.Count > 0).Take(10);
                query.ToList().ForEach(x =>
                    {
                        Console.WriteLine(new String('-', 10));
                        Console.WriteLine(x.SpeakerDisplayName);
                        Console.WriteLine(x.Bio);
                        x.Sessions.ToList().ForEach(y => Console.WriteLine("Session: {0}", y.Title));
                        Console.WriteLine(new String('-', 10));
                    });
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
    }
}

 

The LINQ Query generates following URL:

http://api.visitmix.com/OData.svc/Speakers()?$filter=Sessions/Count gt 0&$top=10

Following the URL leads to an xml output which gives following error

An error occurred while processing this request. Property 'System.Nullable`1[System.DateTime] PublishedDate' is not defined for type 'System.Data.Objects.DataClasses.EntityCollection`1[api.visitmix.com.Session]' System.ArgumentException at System.Linq.Expressions.Expression.Property(Expression expression, PropertyInfo property) at System.Linq.Expressions.Expression.MakeMemberAccess(Expression expression, MemberInfo member) at System.Data.Services.ExpressionVisitor.VisitMemberAccess(MemberExpression m) at System.Data.Services.ExpressionVisitor.Visit(Expression exp) at System.Data.Services.ExpressionVisitor.VisitBinary(BinaryExpression b) at System.Data.Services.ExpressionVisitor.Visit(Expression exp) at System.Data.Services.RequestQueryProcessor.ComposePropertyNavigation(Expression expression, LambdaExpression filterLambda, Boolean propagateNull) at System.Data.Services.Parsing.RequestQueryParser.ExpressionParser.ParseMemberAccess(Expression instance) at System.Data.Services.Parsing.RequestQueryParser.ExpressionParser.ParseIdentifier() at System.Data.Services.Parsing.RequestQueryParser.ExpressionParser.ParsePrimaryStart(ExpressionLexer l) at System.Data.Services.Parsing.RequestQueryParser.ExpressionParser.ParsePrimary() at System.Data.Services.Parsing.RequestQueryParser.ExpressionParser.ParseUnary() at System.Data.Services.Parsing.RequestQueryParser.ExpressionParser.ParseMultiplicative() at System.Data.Services.Parsing.RequestQueryParser.ExpressionParser.ParseAdditive() at System.Data.Services.Parsing.RequestQueryParser.ExpressionParser.ParseComparison() at System.Data.Services.Parsing.RequestQueryParser.ExpressionParser.ParseLogicalAnd() at System.Data.Services.Parsing.RequestQueryParser.ExpressionParser.ParseLogicalOr() at System.Data.Services.Parsing.RequestQueryParser.ExpressionParser.ParseExpression() at System.Data.Services.Parsing.RequestQueryParser.ExpressionParser.ParseWhere() at System.Data.Services.Parsing.RequestQueryParser.ParseLambdaForWhere(IDataService service, ResourceSetWrapper setForIt, ResourceType typeForIt, Type queryElementType, String expression) at System.Data.Services.Parsing.RequestQueryParser.Where(IDataService service, ResourceSetWrapper setForIt, ResourceType typeForIt, IQueryable source, String predicate) at System.Data.Services.RequestQueryProcessor.ProcessFilter() at System.Data.Services.RequestQueryProcessor.ProcessQuery() at System.Data.Services.RequestQueryProcessor.ProcessQuery(IDataService service, RequestDescription description) at System.Data.Services.RequestUriProcessor.ProcessRequestUri(Uri absoluteRequestUri, IDataService service) at System.Data.Services.DataService`1.ProcessIncomingRequestUri() at System.Data.Services.DataService`1.HandleRequest()

This looks strange as I did not use PublishedDate in my code and the service reference was generated entirely by the IDE. On Twitter, I was told that the “Count” filter is invalid. Now, since the query is generated by Linq2OData, the onus is on either OData or on Linq2OData to provide compatible query or generate error while generating the query itself.

I played around a little more and modified the LINQ query as follows

var query = eventEntities.Speakers.Where(x => !String.IsNullOrWhiteSpace(x.Twitter)).Take(10);

This time it gives me following error

{Error translating Linq expression to URI: The expression Not(IsNullOrWhiteSpace([10007].Twitter)) is not supported.}

So, this is established that the LINQ does validate the linq expression before generating the OData uri and also, not all LINQ operators are compatible with OData operators.

I would like to know where the bug resides, in OData or LINQ.

Tagged as: , , No Comments

Lambda based reflection Vs Normal reflection Vs Direct call

Posted on March 25, 2009

One friend of mine sent me the following code sample that really surprised me.

There are three different approaches being used to call a method from a different class. The approaches are -

  1. Direct Call
  2. Call through Lambda based reflection
  3. Call through Normal Reflection

It was really surprising to see the execution speed comparison between three different approaches. The lambda based approach was found to be the fastest by the order of 1000 times.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
 
namespace LambdaReflection
{
 
    class MyClass
    {
        public void CallIt()
        {
        }
    }
 
    class Program
    {
        delegate void LocalDel<t>(T mc);
        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            MethodInfo minfo = typeof(MyClass).GetMethod("CallIt", BindingFlags.Instance | BindingFlags.Public);
            MyClass obj = new MyClass();
 
            //compile expression tree
            LocalDel<myclass> lambdaExpression = FuncCallIt<myclass>("CallIt");
            sw.Reset();
            sw.Start();
 
            //Direct call by using object
            for (int a = 0; a &lt; 10000; a++)
            {
                obj.CallIt();
            }
            sw.Stop();
            Console.WriteLine(string.Format("Time taken by Direct call {0}", sw.ElapsedTicks));
            sw.Reset();
            sw.Start();
 
            //dynamically compiled lambda call
            for (int a = 0; a &lt; 10000; a++)
            {
                lambdaExpression(obj);
            }
            sw.Stop();
            Console.WriteLine(string.Format("Time taken by lambda-expression compilation {0}", sw.ElapsedTicks));
            sw.Reset();
            sw.Start();
 
            //reflection call
            for (int a = 0; a &lt; 10000; a++)
            {
                minfo.Invoke(obj, null);
            }
            sw.Stop();
            Console.WriteLine(string.Format("Time taken by Reflection call {0}", sw.ElapsedTicks));
            Console.ReadLine();
 
        }
        private static LocalDel<t> FuncCallIt<t>(string MethodName)
        {
            var target = Expression.Parameter(typeof(T), "a");
            MethodInfo minfo = typeof(T).GetMethod(MethodName, BindingFlags.Instance | BindingFlags.Public);
            var methodinvokeExpression = Expression.Call(target, minfo);
            var lambda = Expression.Lambda<localdel><t>&gt;(methodinvokeExpression, new ParameterExpression[] { target });
            return lambda.Compile();
        }
    }
}

Following is the result of the execution on my system:

Time taken by Direct call 2384625

Time taken by lambda-expression compilation 902430

Time taken by Reflection call 518534265

I didn’t expect lambda based call to be faster than direct call but I need to explore as how best I can make use of this knowledge in my real programming scenarios. The compiled lambda demands different compiled lambda expressions for each method being used. However, if performance is the prime objective in the application then I think this tangential approach is worth considering.

What is your opinion on it ?

Mark File for deletion on reboot

Posted on March 24, 2009

Requirement: Delete files from a given folder using C#.

Challenge: The file may be in use i.e. locked.

Approach: Use System Call to mark file for deletion on restart

Solution: Use PInvoke for MoveFileEx.

///
/// Consts defined in WINBASE.H
///
internal enum MoveFileFlags
{
    MOVEFILE_REPLACE_EXISTING = 1,
    MOVEFILE_COPY_ALLOWED = 2,
    MOVEFILE_DELAY_UNTIL_REBOOT = 4,
    MOVEFILE_WRITE_THROUGH  = 8
}
 
 
/// <summary>
/// Marks the file for deletion during next system reboot
/// </summary>
/// <param name="lpExistingFileName">The current name of the file or directory on the local computer.</param>
/// <param name="lpNewFileName">The new name of the file or directory on the local computer.</param>
/// <param name="dwFlags">MoveFileFlags</param>
/// <returns>bool</returns>
/// <remarks>http://msdn.microsoft.com/en-us/library/aa365240(VS.85).aspx</remarks>
[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll",EntryPoint="MoveFileEx")]
internal static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName,
MoveFileFlags dwFlags);
 
//Usage for marking the file to delete on reboot
MoveFileEx(fileToDelete, null, MoveFileFlags.MOVEFILE_DELAY_UNTIL_REBOOT);

The file is marked for deletion in registry in following location

HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerPendingFileRenameOperations

Uninstallation from C#

Posted on March 17, 2009

I wanted to programatically uninstall an application installed in my system. Following code is a working piece to uninstall any custom application from the system.

Note: Following code snippet is not the best example of good coding standards ! It was just a sample I was trying to use to achieve something. The code is a mixture of coding styles lifted across various sites. Please excuse for that :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
private static int Uninstall()
{
        Microsoft.Win32.RegistryKey Fregistry =
        Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE")
        .OpenSubKey("Microsoft").OpenSubKey("Windows").OpenSubKey("CurrentVersion")
        .OpenSubKey("Installer").OpenSubKey("UserData")
        .OpenSubKey("S-1-5-18").OpenSubKey("Products");
        string[] Names = Fregistry.GetSubKeyNames();
        string uninstall = "";
        string ApplicationName = "My Custom Application";
        for (int i = 0; i < Names.Length; i++)
        {
            Microsoft.Win32.RegistryKey FTemp = Fregistry.OpenSubKey(Names[i]).OpenSubKey("InstallProperties");
            if (FTemp == null)
                continue;
            string appFound = (FTemp.GetValue("DisplayName") == null) ? String.Empty : FTemp.GetValue("DisplayName").ToString();
            if (!String.IsNullOrEmpty(appFound))
                System.Diagnostics.Trace.WriteLine("Found Software: " + appFound);
            if (String.Compare(appFound, ApplicationName, true) == 0)
            {
                String installedVersion = FTemp.GetValue("DisplayVersion").ToString();
                if (!installedVersion.StartsWith("3.1."))//can be removed if only one version is installed
                    continue;
                object obj = FTemp.GetValue("UninstallString");
                if (obj == null)
                    uninstall = "";
                else
                    uninstall = obj.ToString();
                i = Names.Length;
            }
        }
        if (String.IsNullOrEmpty(uninstall))
        {
            return -1;
        }
        System.Console.WriteLine(uninstall);
        System.Diagnostics.Process FProcess = new System.Diagnostics.Process();
        string temp = "/passive /x{" + uninstall.Split("/".ToCharArray())[1].Split("I{".ToCharArray())[2];
        FProcess.StartInfo.FileName = uninstall.Split("/".ToCharArray())[0];
        FProcess.StartInfo.Arguments = temp;
        FProcess.StartInfo.UseShellExecute = false;
        FProcess.Start();
        FProcess.WaitForExit();
        if (FProcess.ExitCode != 0)
            return -1;
        else
        {
            return 0;
        }
}
Tagged as: , No Comments

MSDN code examples could be incorrect as well

Posted on September 8, 2008

It was really odd for me to find an error in MSDN code example which took almost a couple of hours to figure out what is wrong. I am working in VSTO (Visual Studio Tool for Office). I am developing a plugin which is suppose to override some of the specific Office 2007 functionalities and implement some custom actions. My quest for knowledge took me here. I found this page very interesting and I found the explanation for exactly what was required. I took the C# code example as it is and tried to play around in my own sample. Sadly, the example which is given on the page in C# has a flaw.

public void mySave(IRibbonControl control, bool cancelDefault)
{
    If (repurposing)
    {
        MessageBox.Show("The Save button has been temporarily repurposed.");
        cancelDefault = False;
    }
    else
    {
        cancelDefault = False;
    }
}

In this code example, the second parameter should be a reference type. Visual basic example in the same MSDN page shows it correctly but the C# example as given above is incorrect. I respect MSDN so much that I didn't care to see if anything is wrong in the code I lifted. After fiddeling around with a number of things and learning a whole lot than intended, I found the problem.
Lesson learnt! I will be more careful from next time :)