Entity Framework Profiler with IronRuby and IronPython Scripting
Because I would like to write my Repositories and monitor their behaviour in the Profiler I decided that I could kill two birds with one console (so to speak). The first bird to kill involved my spending as much time as possible in the pursuit of both learning IronRuby and gaining better understanding of the more interesting problems that can be solved with dynamic languages implemented on top of the DLR. I can see the possibilities of hosting the DLR to provide scripting support to applications and after having implemented my own hosted IronRuby consoles I eventually decided to reuse one that was more fully featured, saving me quite a bit of time by best fitting the Profiler’s needs. The console I chose in the end was IronEditor which is available on codeplex. IronEditor is implemented as a Windows Forms application and so I did have to refactor it a little to make it work as User Control and have the UI behave correctly for asynchronous updates to the UI. Hosting the Windows User Control in the WPF Profiler was of course simple enough by leveraging the WindowsFormsHost.
I had already posted about what to expect from the next iteration of the Profiler and I won’t repeat it here, so if your new to the tool I suggest you look here. One further change I flagged was to remove WCF from the application and have the messaging occur via sockets. I decided against that change and chose instead (see below) to take the opportunity to demonstrate how to use WCF UnTyped Messages with a bit of IoC to achieve a more loosely coupled approach to handling messages. This approach requires writing specific handlers for specific messages that are not in any way coupled to the signature of any RPC / CRUD looking ServiceContract or the shape of any DataContract, and it is a style somewhat (largely) borrowed from NServiceBus. Here’s the code from the WCF Service and I will have more to say on that a bit later with a more detailed post.
Messaging
public void SendAny(Message message) { object msg_in_body = null; var container = new Castle.Windsor.WindsorContainer(); //get all the potential handlers in the assembly //NOTE: could load all these up at startup and call //to find one that matches from memory rather than //in the same iteration that adds the components //to the container. var libTypes = from a in Assembly.GetExecutingAssembly().GetTypes() from i in a.GetInterfaces() from ii in i.GetInterfaces() from g in i.GetGenericArguments() from gi in g.GetInterfaces() where ii.IsAssignableFrom(typeof(IMessageHandler)) where gi.IsAssignableFrom(typeof(IMessage)) select new { TheType = a, TheIface = i, TheGeneric = g, TheGenericIface = gi }; //iterate all the handlers foreach (var gen in libTypes) { container.AddComponent(gen.TheType.Name, gen.TheType); //attempt to deserialize using the current //handlers generic argument (the message) msg_in_body = MessageSerializer.DeserializeMessage (message, gen.TheGeneric); if (msg_in_body != null) { //resolve the message handler in the container var the_handler = container.Resolve(gen.TheType); var handle_method = the_handler.GetType().GetMethod(“Handle”); if(handle_method != null) handle_method.Invoke(the_handler, new[] { msg_in_body }); } } }
The Messages And Message Handlers
public interface IMessage { Guid MessageID { get; } } public interface IMessageHandler { } public interface IMessageHandler<TMessage> : IMessageHandler where TMessage : IMessage { void Handle(TMessage message); } public class EntityInterceptMessage : IMessage { [XmlElement(Order = 1)] public Guid MessageID { get { return _id; } set { _id = value; } } [XmlElement(Order = 2)] public string SqlQueryText { get { return _sql; } set { _sql = value; } } [XmlElement(Order = 3)] public string ProcessID { get { return _processId; } set { _processId = value; } } //….message members etc } public class EntityInterceptMessageHandler : IMessageHandler<EntityInterceptMessage> { public void Handle(EntityInterceptMessage message) { ProfilerModel.EntityMessages.Add(message); Console.WriteLine(message.EntityModelName); } }
Running the Application
You can run this code and test it using a supplied IronRuby script named “run_profiler_script.rb”, just make sure you have the Northwind database installed , that the script gets the required changes to match your database details and that the the test projects DLL is ‘required’ from the appropriate location on your hard drive.
require ‘D:/simon.segal/Local Working/Org.TechA.EF.Profiler’ + ‘/Org.TechA.EF.Profiler.Tests/bin/Debug’ + ‘/Org.TechA.EF.Profiler.Tests.dll’
By downloading you will be accepting the code project open license for the SQL CodeBox control and the Apache License 2.0 for IronEditor, both of which have been integrated into this solution. You can download the Profiler from here.
UPDATE: (Sunday April 19th)
Apologies for having an earlier link to the code being incomplete. The problem has now been rectified.
5 Comments so far
Leave a reply









[...] my part so far I have delved into IronRuby and started to employ it for scripting my C# applications. Why did I choose IronRuby over IronPython? It began with curiosity in the Ruby language in general [...]
do you plan to release the profiler?
1. would it work with EF 4.0?
2. have you looked on NHibernate profiler? buying the source code would help you, awesome project:
http://nhprof.com/
I wouldn’t mind paying for the project if it would be on par with NHProf. Well if you need to fund your developement just drop me a mail, sophisticated EF profiler would be first step for us to transfer from NHibernate ORM.
good job
[Reply]
Uzivatel
1. It would work with EF 4.0 however I am purposefully delayed moving it’s development forward in a meaningful way until EF 4.0 started to become somewhat stable (now).
2. I am aware of NHPROF (the impetus for the EF Prof) but I hadn’t considered taking this project to a commercial point. Let me ponder it a bit.
The application really kinda grew out of a set of experiments to see what I could achieve with PostSharp to address some of EF’s weak points and also lead to a framework that supported implicit lazy loading with fetching strategies, specifications for dynamic querying and a Repository pattern implementation, all of which I blogged about here extensively. This story has changed with EF 4.0 (supports POCO, lazy loading etc) and PostSharp is no longer required and the EF Profiler will therefore need a re factored design approach.
[Reply]
OK thanks for the answer, I haven’t followed EF v1 as this was a really inferior product to NHibernate, but now that EF v4 is looking very promising (even in beta) we are finding it superior to NHibernate in few ways.
But the profiler is missing as the generated SQL isn’t on par with NHibernate yet, but NH doesn’t have a LINQ (proper) yet so it is apple and oranges.
Still, this is the only profiler for EF I found, anyway, good luck with EF v4, you should adopt it asap as I don’t really see a point why not (except .net v4 dependency)
[Reply]
Yes I agree and have already begun adopting EF V 4.0. I am in the process of redesigning my framework libraries that assist me working with it in the style of development that I prefer (DDD). I have posted on this already and will be following with more in the coming weeks.
[Reply]