Real-time Google Analytics with MVVM

by Geert 18. January 2012 21:13

Inside Catel, there are several secret gems. One of these gems is the possibility to audit everything that happens in the view models (property changes, events, commands, etc). This is very useful for logging, or in the case of this blog post, real-time tracking with Google Analytics.

Show me first

Below is a movie that demonstrates the example application with real-time tracking:

Cool, now show me the code

The code is pretty simple. First you need to create an implementation of the IAuditor interface. The prevent that you need to implement all methods, there is a convenience implementation in the form of the AuditorBase. For the Google Analytics implementation, we use Web-Analysis.net (also used in the Microsoft Silverlight Analytics Framework).

   1: /// <summary>
   2: /// Google Analytics auditor.
   3: /// </summary>
   4: public class GoogleAnalytics : AuditorBase
   5: {
   6:     private readonly ApplicationTracker _appTracker;
   7:  
   8:     public GoogleAnalytics(string apiKey, string applicationName)
   9:     {
  10:         Argument.IsNotNull("apiKey", apiKey);
  11:         Argument.IsNotNull("applicationName", applicationName);
  12:  
  13:         _appTracker = new ApplicationTracker(apiKey, applicationName);
  14:         _appTracker.StartSession();
  15:     }
  16:  
  17:     public override void OnCommandExecuted(IViewModel viewModel, string commandName, ICatelCommand command, object commandParameter)
  18:     {
  19:         _appTracker.TrackEvent(ApplicationTrackerCategories.Command, string.Format("{0}.{1}", viewModel.GetType().Name, commandName));
  20:     }
  21:  
  22:     public override void OnViewModelCreated(Type viewModelType)
  23:     {
  24:         _appTracker.TrackPageView(viewModelType.Name);
  25:  
  26:         _appTracker.TrackCustomEvent("ViewModel.Created", viewModelType.Name);
  27:     }
  28:  
  29:     public override void OnViewModelCanceled(IViewModel viewModel)
  30:     {
  31:         _appTracker.TrackCustomEvent("ViewModel.Canceled", viewModel.GetType().Name);
  32:     }
  33:  
  34:     public override void OnViewModelSaved(IViewModel viewModel)
  35:     {
  36:         _appTracker.TrackCustomEvent("ViewModel.Saved", viewModel.GetType().Name);
  37:     }
  38:  
  39:     public override void OnViewModelClosed(IViewModel viewModel)
  40:     {
  41:         _appTracker.TrackCustomEvent("ViewModel.Closed", viewModel.GetType().Name);
  42:     }
  43: }

Last but not least, you need to register the auditor in the AuditorManager.

   1: AuditingManager.RegisterAuditor(new GoogleAnalytics(myApiKey, "Catel Analytics Example"));

Easy huh, creating real-time Google Analytics for your app Glimlach. The advantages is that you can now see exactly what your users are doing and what features of your application are used most (and thus should have a higher priority for support calls).

Tags: ,

C# | MVVM

Care when unit testing via Resharper and MsTest

by Geert 13. January 2012 12:54

I like unit tests. So much that I wrote 1003 for Catel to make sure we don’t introduce bugs when changing code. We also love automation, so we use build scripts to create a new (beta) release, create a nuget package and upload the beta versions including symbols.

Anyway, enough history, let’s get to the problem. This week, I fixed an issue that as soon as a ReflectionTypeLoadException occurred, the successfully loaded types were not used by Catel either. That is wrong, so we fixed it. We always run the unit tests using Resharper and dotCover and all succeeded. However, as soon as we ran the unit tests in msbuild (which uses mstest), 3 unit tests failed. It was about this particular code:

   1: public static Type[] GetAllTypesSafely(Assembly assembly, bool logLoaderExceptions)
   2: {
   3:     Argument.IsNotNull("assembly", assembly);
   4:  
   5:     Type[] foundAssemblyTypes;
   6:  
   7:     try
   8:     {
   9:         foundAssemblyTypes = assembly.GetTypes();
  10:     }
  11:     catch (ReflectionTypeLoadException typeLoadException)
  12:     {
  13:         foundAssemblyTypes = typeLoadException.Types;
  14:  
  15:         Log.Warning("A ReflectionTypeLoadException occured, adding all {0} types that were loaded correctly", foundAssemblyTypes.Length);
  16:  
  17:         if (logLoaderExceptions)
  18:         {
  19:             Log.Warning("The following loading exceptions occurred:");
  20:             foreach (var error in typeLoadException.LoaderExceptions)
  21:             {
  22:                 Log.Warning("  " + error.Message);
  23:             }
  24:         }
  25:     }
  26:  
  27:     return foundAssemblyTypes;
  28: }

According to the documentation, the ReflectionTypeLoaderException.Types contains all the successfully loaded types. However, when running the unit tests (which loads more assemblies into the current AppDomain), the array contained 3 instances of null.

WTF? A successfully loaded type that is null? /*sarcasme on*/ I bet the Microsoft engineers had a good reason for this /*sarcasm off*/. Anyway, I fixed the issue by filtering out the null values. Below is the fixed code (notice the LINQ expression):

   1: public static Type[] GetAllTypesSafely(Assembly assembly, bool logLoaderExceptions)
   2: {
   3:     Argument.IsNotNull("assembly", assembly);
   4:  
   5:     Type[] foundAssemblyTypes;
   6:  
   7:     try
   8:     {
   9:         foundAssemblyTypes = assembly.GetTypes();
  10:     }
  11:     catch (ReflectionTypeLoadException typeLoadException)
  12:     {
  13:         foundAssemblyTypes = (from type in typeLoadException.Types
  14:                                 where type != null
  15:                                 select type).ToArray();
  16:  
  17:         Log.Warning("A ReflectionTypeLoadException occured, adding all {0} types that were loaded correctly", foundAssemblyTypes.Length);
  18:  
  19:         if (logLoaderExceptions)
  20:         {
  21:             Log.Warning("The following loading exceptions occurred:");
  22:             foreach (var error in typeLoadException.LoaderExceptions)
  23:             {
  24:                 Log.Warning("  " + error.Message);
  25:             }
  26:         }
  27:     }
  28:  
  29:     return foundAssemblyTypes;
  30: }

So, what have we learned today? Even unit tests cannot be trusted…

Tags: , ,

C#

Using true weak actions without causing memory leaks

by Geert 29. December 2011 16:01

Recently I needed weak actions for the message mediator implementation of Catel. I looked at a few examples and most seem to do something like this:

   1: public class WeakAction
   2: {
   3:     private readonly Action _action;
   4:     private WeakReference _reference;
   5:     
   6:     public WeakAction(object target, Action action)
   7:     {
   8:         _reference = new WeakReference(target);
   9:         _action = action;
  10:     }
  11:     
  12:     public bool IsAlive
  13:     { 
  14:         get { return (_reference != null) ? _reference.IsAlive : false; }
  15:     }    
  16:     
  17:     public void Execute()
  18:     {
  19:         if (_action != null && IsAlive)
  20:         {
  21:             _action();
  22:         }
  23:     }    
  24: }

There are 2 downsides of this approach:

  1. It doesn’t allow static handlers
  2. It causes memory leaks

The problem

So if you are using such an implementation of a weak action, all your alarm bells should be ringing right now. The issue is in the storage of the Action object. The action is a method handler. To be able to call the handler, it must store the reference (as Target property on the Action class) of the target.

However, this means that there is now a reference to the target, so the target can never be garbage collected, so you are now dealing with a big issue in your application because you think that you are using weak events, but you aren’t.

The Solution

I already wrote a true weak event listener once, so this one should be easy. What you basically need to do is to write an open instance delegate, create a handler without a target for it and late-bind the handler. Sounds complex, but once you get the grip of it, it’s pretty simple. Below is the code for a non-generic Action. All this code (and the generic implementation) can be found at http://catel.codeplex.com.

   1: public class WeakAction
   2: {
   3:     public delegate void OpenInstanceAction<TTarget>(TTarget @this);
   4:     private Delegate _action;
   5:     private WeakReference _reference;
   6:     
   7:     public WeakAction(object target, Action action)
   8:     {
   9:         _reference = new WeakReference(target);
  10:         
  11:         var targetType = (target != null) ? target.GetType() : typeof(object);
  12:         var delegateType = typeof(OpenInstanceAction<>).MakeGenericType(targetType);
  13:  
  14:         _action = Delegate.CreateDelegate(delegateType, null, action.Method);        
  15:     }
  16:     
  17:     public bool IsAlive
  18:     { 
  19:         get { return (_reference != null) ? _reference.IsAlive : false; }
  20:     }    
  21:     
  22:     public void Execute()
  23:     {
  24:         if (_action != null && IsAlive)
  25:         {
  26:             _action.DynamicInvoke(_reference.Target);
  27:         }
  28:     }    
  29: }

Tags: ,

C# | Catel

Dealing with generic nested types

by Geert 29. December 2011 15:50

Recently I was working on true weak actions and wanted to do something like this:

   1: public class WeakAction<TParameter>
   2: {
   3:     public delegate void OpenInstanceGenericAction<TTarget>(TTarget @this, TParameter parameter);
   4:  
   5:     public WeakAction(object target, Action<TParameter> action)
   6:     {
   7:         var targetType = (target != null) ? target.GetType() : typeof(object);
   8:         var delegateType = typeof(OpenInstanceGenericAction<>).MakeGenericType(targetType, typeof(TParameter));
   9:  
  10:         _action = Delegate.CreateDelegate(delegateType, null, action.Method);
  11:     }
  12: }

I was pretty sure I was doing it all right. In this code, I create a generic open instance handler to make sure I can invoke the method without referencing the instance itself. This allows me to write true weak actions.

Anyway, the error that pops up is:

System.ArgumentException: Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.

Scratching my head over and over again, for about 1 hour, something came into my mind that couldn’t be true: would it be that I have to define the TParameter first, and then the TTarget, even when the delegate uses them in another order?

The answer seemed to be yes!

Apparently, you need to specify the order of arguments. So, because the delegate is part of a class defining the first generic argument (TParameter), you need to specify that first. So, it is not the order in which they are used inside the delegate, but the order of definition.

Tags:

C# | Catel

Get binding expressions of DependencyObject instances in Silverlight

by Geert 22. December 2011 19:11

Recently, I needed to retrieve binding information on a dependency property in a behavior. In WPF, this is all possible (of course) via the BindingOperations.GetBindingExpression method. However, the developers of Silverlight must have thought that developers are only interested in binding expressions starting from a FrameworkElement. So, this means you cannot get binding expressions from the following types while they can have bindings:

  • DependencyObject
  • UIElement
  • Behavior
  • TriggerAction
  • TriggerBase

And much more. For a complete list, see this list.

Anyway, I was pretty sad that the Silverlight team decided for me that I would never need to check the binding expression inside a behavior (which I needed in this case). Anyway, below is an extension method that allows you to get the binding expression of any dependency property:

   1: /// <summary>
   2: /// Gets the binding expression for the specified dependency property.
   3: /// </summary>
   4: /// <param name="dependencyObject">The dependency object.</param>
   5: /// <param name="dependencyProperty">The dependency property.</param>
   6: /// <returns>
   7: /// The <see cref="BindingExpression"/> or <c>null</c> if the property is not bound.
   8: // </returns>
   9: /// <exception cref="ArgumentNullException">The <paramref name="dependencyObject"/> is <c>null</c>.</exception>
  10: /// <exception cref="ArgumentNullException">The <paramref name="dependencyProperty"/> is <c>null</c>.</exception>
  11: public static BindingExpression GetBindingExpression(this DependencyObject dependencyObject, DependencyProperty dependencyProperty)
  12: {
  13:     Argument.IsNotNull("dependencyObject", dependencyObject);
  14:     Argument.IsNotNull("dependencyProperty", dependencyProperty);
  15:  
  16:     return (dependencyObject.ReadLocalValue(dependencyProperty) as BindingExpression);
  17: }

Of course, this extension method is included in Catel.

Tags:

C# | Silverlight

About the Author

Geert van Horrik is a independent freelance software developer since January 1st, 2007. Since then he was been working on several projects from C++ to C# (WPF, ASP.NET, etc). Currently he loves to write his software using WPF (or Silverlight if WPF isn't an option).

Lately, Geert is spending a lot of time on Catel, a free open-source MVVM Framework for WPF and Silverlight. Actually, it's more than "just" an MVVM Framework, it's a complete application library!