Tag Archives: C#

Testing that all Fault Exceptions are being handled in a WCF client

One of the things that the .Net compiler won’t warn developers about, is when another developer decides to add a new FaultException type and the client code isn’t updated to handle this new type of exception. The solution I’m demonstrating here is a generic solution to check for this, but implies that the client is going through a ChannelFactory and not a ClientBase implementation.

ChannelFactory implementations are usually better if there’s full ownership, in the institution, of service and clients. The share of the service contracts will allow Continuous Integration builds to fail if there was a breaking change made on the service that broke one or more of the consuming clients. You may argue that ChannelFactory implementations have the issue that if you change the service, with a non-breaking change, you need to re-test and re-deploy all your clients code: This isn’t exactly true, as if it is a non-breaking change, all the clients will continue to work even with a re-deploy of the service.

Default ChannelFactory Wrapper

The generic implementation depends on our default WcfService wrapper for a ChannelFactory. This could be abstracted through an interface that had the Channel getter on it, and make the generic method depend on the interface instead of the actual implementation.

I will provide here a simple implementation of the ChannelFactory wrapper:


public class WcfService<T> : IDisposable where T : class
{
private readonly object _lockObject = new object();
private bool _disposed;
private ChannelFactory<T> _factory;
private T _channel;
internal WcfService()
{
_disposed = false;
}
internal virtual T Channel
{
get
{
if (_disposed)
{
throw new ObjectDisposedException("Resource WcfService<" + typeof(T) + "> has been disposed");
}
lock (_lockObject)
{
if (_factory == null)
{
_factory = new ChannelFactory<T>("*"); // First qualifying endpoint from the config file
_channel = _factory.CreateChannel();
}
}
return _channel;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
internal void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (!disposing)
{
return;
}
lock (_lockObject)
{
if (_channel != null)
{
try
{
((IClientChannel)_channel).Close();
}
catch (Exception)
{
((IClientChannel)_channel).Abort();
}
}
if (_factory != null)
{
try
{
_factory.Close();
}
catch (Exception)
{
_factory.Abort();
}
}
_channel = null;
_factory = null;
_disposed = true;
}
}
}

view raw

gistfile1.cs

hosted with ❤ by GitHub

Example of a client using the Wrapper

Here’s an example of code that we want to test, for a client that’s using the WcfService wrappe. The separation from the method that creates the WcfService wrapped in a using clause and the internal static one is just for testing purposes, just so we can inject a WcfService mock and assert against it. The client successfully wraps a FaultException into something meaningful for the consuming application.


public class DocumentClient : IDocumentService
{
public string InsertDocument(string documentClass, string filePath)
{
using (var service = new WcfService<IDocumentService>())
{
return InsertDocument(documentClass, filePath, service);
}
}
internal static string InsertDocument(string documentClass, string filePath, WcfService<IDocumentService> service)
{
try
{
return service.Channel.InsertDocument(documentClass, filePath);
}
catch (FaultException<CALFault> ex)
{
throw new DocumentCALException(ex);
}
catch (Exception ex)
{
throw new ServiceUnavailableException(ex.Message, ex);
}
}
}

view raw

gistfile1.cs

hosted with ❤ by GitHub

The generic Fault contract checker

This implementation is using Moq as the Mocking framework and the code is dependent on it. It also provides signatures up to 4 exceptions that are expected, this is done with a Top-Down approach, where the signature with the most type parameters has the full implementation and the others just call the one that’s one higher level in the signature chain. To support this mind set, a special empty DummyException is declared to fill the gaps between Type Parameters in the different signatures.

Breaking down the code, what it is doing is creating a dynamic Expression Tree that we can wire in the Setup method of the client mock that will intercept calls with any type of parameter (It.IsAny). Then for each FaultContractAttribute that is decorating the service, instantiate it and wire everything so that the service method is setup to throw it. Finally call it, and check if it was caught and wrapped or if we are getting the original FaultException back.


public static class ContractCheckerExtension
{
public static string CheckFaultContractMapping<TContract, TEx1>(this MethodInfo method, Action<Mock<WcfService<TContract>>> action)
where TContract : class
where TEx1 : Exception
{
return method.CheckFaultContractMapping<TContract, TEx1, DummyException>(action);
}
public static string CheckFaultContractMapping<TContract, TEx1, TEx2>(this MethodInfo method, Action<Mock<WcfService<TContract>>> action)
where TContract : class
where TEx1 : Exception
where TEx2 : Exception
{
return method.CheckFaultContractMapping<TContract, TEx1, TEx2, DummyException>(action);
}
public static string CheckFaultContractMapping<TContract, TEx1, TEx2, TEx3>(this MethodInfo method, Action<Mock<WcfService<TContract>>> action)
where TContract : class
where TEx1 : Exception
where TEx2 : Exception
where TEx3 : Exception
{
return method.CheckFaultContractMapping<TContract, TEx1, TEx2, TEx3, DummyException>(action);
}
public static string CheckFaultContractMapping<TContract, TEx1, TEx2, TEx3, TEx4>(this MethodInfo method, Action<Mock<WcfService<TContract>>> action)
where TContract : class
where TEx1 : Exception
where TEx2 : Exception
where TEx3 : Exception
where TEx4 : Exception
{
// we're creating a lambda on the fly that will call on the target method
// with all parameters set to It.IsAny<[the type of the param]>.
var lambda = Expression.Lambda<Action<TContract>>(
Expression.Call(
Expression.Parameter(typeof (TContract)),
method,
CreateAnyParameters(method)),
Expression.Parameter(typeof (TContract)));
// for all the fault contract attributes that are decorating the method
foreach (var faultAttr in method.GetCustomAttributes(typeof(FaultContractAttribute), false).Cast<FaultContractAttribute>())
{
// create the specific exception that get's thrown by the fault contract
var faultDetail = Activator.CreateInstance(faultAttr.DetailType);
var faultExceptionType = typeof(FaultException<>).MakeGenericType(new[] { faultAttr.DetailType });
var exception = (FaultException)Activator.CreateInstance(faultExceptionType, faultDetail);
// mock the WCF pipeline objects, channel and client
var mockChannel = new Mock<WcfService<TContract>>();
var mockClient = new Mock<TContract>();
// set the mocks
mockChannel.Setup(x => x.Channel)
.Returns(mockClient.Object);
mockClient.Setup(lambda)
.Throws(exception);
try
{
// invoke the client, wrapped in an Action delegate
action(mockChannel);
}
catch (Exception ex)
{
// if we get a targeted exception it's because the fault isn't being handled
// and we return with the type of the fault contract detail type that was caught
if (ex is TEx1 || ex is TEx2 || ex is TEx3 || ex is TEx4)
return faultAttr.DetailType.FullName;
// else soak all other exceptions because we are expecting them
}
}
return null;
}
private static IEnumerable<Expression> CreateAnyParameters(MethodInfo method)
{
return method.GetParameters()
.Select(p => typeof (It).GetMethod("IsAny").MakeGenericMethod(p.ParameterType))
.Select(a => Expression.Call(null, a));
}
}
[Serializable]
public class DummyException : Exception
{
}

view raw

gistfile1.cs

hosted with ❤ by GitHub

Here’s a sample of a unit test using the ContractChecker for the example client showed previously in the post:


[TestMethod]
public void Ensure_InsertDocument_FaultContracts_AreAllMapped()
{
var targetOperation = typeof (IDocumentService).GetMethod(
"InsertDocument",
new[]
{
typeof (string),
typeof (string)
});
var result = targetOperation.CheckFaultContractMapping<IDocumentService, ServiceUnavailableException>(
m => DocumentClient.InsertDocument(string.Empty, string.Empty, m.Object));
Assert.IsNull(result, "The type {0} used to detail a FaultContract isn't being properly handled on the Service client", result);
}

view raw

gistfile1.cs

hosted with ❤ by GitHub

Unit Testing IBM Websphere MQ with Fakes

.Net Projects that target the IBM Websphere MQ objects are often hard to unit test. Even with some amount of effort in isolating all the MQ objects through Dependency Injection and some tweaks around stubbing some of the common MQ classes, it’s easy to get into trouble with NullReferenceExceptions being thrown.

When targeting IBM MQ, there are two separate options: The native libraries (amqmdnet.dll) or the IBM.XMS library. I have found the JMS .Net implementation very problematic and hiding important queue options from the consuming classes, so I use mostly the native libraries and those are the focus of this post.

I won’t cover the basic principles of starting to use fakes, many people have covered that already and MSDN has a very nice series of articles on that. I will just highlight some common utility code and tricks I have learned along the way.

IBM MQ Design considerations

When I’m targeting IBM MQ, there’s a common set of design choices I make, and some of the code samples will reflect these options:

  • I always browse messages first. Only after I have actually done what I need to do with the messages, I do a read on them.
  • I use Rx right after the queues, this is why I always browse first. Once a message is browsed I push it through an IObservable, so that later I can do things like filter, sort, throttle, etc.
  • I use System.Threading Timers to do pooling on the MQ queues. They do a very nice usage of threads and they also allow me to change the pooling frequency at run-time.
  • Although I use several mocking frameworks, I tend to use only one per test class. On the test examples, everything will be going through Fakes, but I can easily argue that Fakes isn’t as mature as Moq or Rhino Mocks when it comes to fluent writing and API productivity.

IBM MQ id fields and properties

One common task around testing MQ objects is playing around with their Ids, either the object Id or other Ids like the correlation Id. These are always byte arrays and most times they are fixed size, so I wrote a nice utility method for creating fixed sized arrays:


private static byte[] CreateByteArray(int size, byte b)
{
var array = new byte[size];
for (var i = 0; i < array.Length; i++)
{
array[i] = b;
}
return array;
}

view raw

gistfile1.cs

hosted with ❤ by GitHub

To assert the different Id fields just use CollectionAssert and use the ToList on both byte arrays.

CollectionAssert.AreEqual(messageId.ToList(), message.MessageId.ToList());

IBM MQ Shims tips and tricks

One of the problems you will see when you start using IBM.WMQ Shims is null references when instantiating some objects. This is easily fixed by overriding the constructors on the Shims:

ShimMQQueueManager.ConstructorStringHashtable = (_, __, ___) => { };
ShimMQMessage.ConstructorMQMessage = (_, __) => { };

Some of the objects in IBM.WMQ have a long inheritance chain. Shims don’t follow this, so for example, if you’re doing a Get on a queue with MQMessage and MQGetMessageOptions, this exists in MQDestination that MQQueue inherits from, so to be able to stub this method you need to write something like this:

ShimMQDestination.AllInstances.GetMQMessageMQGetMessageOptions = (_, message, options) =>
{
    Assert.AreEqual(MQC.MQGMO_NONE, options.Options);
    Assert.AreEqual(MQC.MQMO_MATCH_MSG_ID, options.MatchOptions);
    CollectionAssert.AreEqual(messageId.ToList(), message.MessageId.ToList());
};

Open Queue example with the corresponding tests

Here’s a full example of a method that Opens a Queue for reading and/or writing


/// <summary>
/// Opens this queue. Supports listening and writing options, if setup
/// for listening it will do browse and not really reads from the queue
/// as messages arrive to the queue.
/// </summary>
/// <param name="reading">True if we want to read from this queue, false otherwise.</param>
/// <param name="writing">True if we want to write to this queue, false otherwise.</param>
/// <returns>The Observable where all the messages read from this queue will appear.</returns>
public IObservable<IServiceMessage> OpenConnection(bool reading = true, bool writing = false)
{
// create the properties HashTable
var mqProperties = new Hashtable
{
{ MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED },
{ MQC.HOST_NAME_PROPERTY, ConfigurationProvider.MQMessageListenerHostName },
{ MQC.PORT_PROPERTY, ConfigurationProvider.MQMessageListenerPortNumeric },
{ MQC.CHANNEL_PROPERTY, ConfigurationProvider.MQMessageListenerChannelName }
};
// create the queue manager
_queueManager = new MQQueueManager(ConfigurationProvider.MQMessageListenerQueueManagerName, mqProperties);
// deal with the queue open options
var openOptions = MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING;
if (reading)
{
openOptions += MQC.MQOO_BROWSE;
}
if (writing)
{
openOptions += MQC.MQOO_OUTPUT;
}
// create and start the queue, check for potential bad queue names
try
{
Queue = _queueManager.AccessQueue(QueueName, openOptions);
}
catch (MQException ex)
{
if (ex.ReasonCode == 2085)
{
throw new ConfigurationErrorsException(string.Format(CultureInfo.InvariantCulture, "Wrong Queue name: {0}", QueueName));
}
throw;
}
if (reading)
{
StartListening();
}
return Stream.AsObservable();
}

view raw

gistfile1.cs

hosted with ❤ by GitHub

And the unit tests that test it


/// <summary>
/// Tests that OpenConnection creates the proper MQQueueManager and accesses the
/// queue with the right set of options.
/// </summary>
[TestMethod]
public void Test_OpenConnection_GoesThrough()
{
const string host = "some random host";
const string channel = "some random channel";
const string manager = "some random manager";
const string queueName = "some random queue";
const int port = 1234;
var startListeningCall = false;
using (ShimsContext.Create())
{
var configShim = new ShimConfigurationProvider
{
MQMessageListenerChannelNameGet = () => channel,
MQMessageListenerHostNameGet = () => host,
MQMessageListenerPortNumericGet = () => port,
MQMessageListenerQueueManagerNameGet = () => manager
};
ShimMQQueueManager.ConstructorStringHashtable = (_, s, options) =>
{
Assert.AreEqual(manager, s);
Assert.AreEqual(host, options[MQC.HOST_NAME_PROPERTY]);
Assert.AreEqual(channel, options[MQC.CHANNEL_PROPERTY]);
Assert.AreEqual(port, options[MQC.PORT_PROPERTY]);
Assert.AreEqual(MQC.TRANSPORT_MQSERIES_MANAGED, options[MQC.TRANSPORT_PROPERTY]);
};
ShimMQQueueManager.AllInstances.AccessQueueStringInt32 = (_, s, options) =>
{
Assert.AreEqual(MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING, options);
Assert.AreEqual(queueName, s);
return null;
};
var mqShim = new ShimMQMessageQueue
{
InstanceBehavior = ShimBehaviors.Fallthrough,
ConfigurationProviderGet = () => configShim.Instance,
QueueNameGet = () => queueName,
StreamGet = () => new Subject<IServiceMessage>(),
StartListening = () => { startListeningCall = true; }
};
mqShim.Instance.OpenConnection(false);
Assert.IsFalse(startListeningCall);
}
}
/// <summary>
/// Tests the OpenConnection options in the queue access when the queue is setup to read.
/// It also ensures that StartListening is called if the queue is opened for reading.
/// </summary>
[TestMethod]
public void Test_OpenConnection_ForReading()
{
const string queueName = "some random queue";
var startListeningCall = false;
using (ShimsContext.Create())
{
ShimMQQueueManager.ConstructorStringHashtable = (_, __, ___) => { };
ShimMQQueueManager.AllInstances.AccessQueueStringInt32 = (_, s, options) =>
{
Assert.AreEqual(MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING + MQC.MQOO_BROWSE, options);
Assert.AreEqual(queueName, s);
return null;
};
var mqShim = new ShimMQMessageQueue
{
InstanceBehavior = ShimBehaviors.Fallthrough,
ConfigurationProviderGet = () => new ShimConfigurationProvider().Instance,
QueueNameGet = () => queueName,
StreamGet = () => new Subject<IServiceMessage>(),
StartListening = () => { startListeningCall = true; }
};
mqShim.Instance.OpenConnection();
Assert.IsTrue(startListeningCall);
}
}
/// <summary>
/// Tests the OpenConnection options in the queue access when the queue is setup to write.
/// </summary>
[TestMethod]
public void Test_OpenConnection_ForWriting()
{
const string queueName = "some random queue";
var startListeningCall = false;
using (ShimsContext.Create())
{
ShimMQQueueManager.ConstructorStringHashtable = (_, __, ___) => { };
ShimMQQueueManager.AllInstances.AccessQueueStringInt32 = (_, s, options) =>
{
Assert.AreEqual(MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING + MQC.MQOO_OUTPUT, options);
Assert.AreEqual(queueName, s);
return null;
};
var mqShim = new ShimMQMessageQueue
{
InstanceBehavior = ShimBehaviors.Fallthrough,
ConfigurationProviderGet = () => new ShimConfigurationProvider().Instance,
QueueNameGet = () => queueName,
StreamGet = () => new Subject<IServiceMessage>(),
StartListening = () => { startListeningCall = true; }
};
mqShim.Instance.OpenConnection(false, true);
Assert.IsFalse(startListeningCall);
}
}
/// <summary>
/// Tests the OpenConnection options in the queue access when the queue is setup to
/// read and write at the same time.
/// It also ensures that StartListening is called if the queue is opened for reading.
/// </summary>
[TestMethod]
public void Test_OpenConnection_ForReadingAndWriting()
{
const string queueName = "some random queue";
var startListeningCall = false;
using (ShimsContext.Create())
{
ShimMQQueueManager.ConstructorStringHashtable = (_, __, ___) => { };
ShimMQQueueManager.AllInstances.AccessQueueStringInt32 = (_, s, options) =>
{
Assert.AreEqual(MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING + MQC.MQOO_BROWSE + MQC.MQOO_OUTPUT, options);
Assert.AreEqual(queueName, s);
return null;
};
var mqShim = new ShimMQMessageQueue
{
InstanceBehavior = ShimBehaviors.Fallthrough,
ConfigurationProviderGet = () => new ShimConfigurationProvider().Instance,
QueueNameGet = () => queueName,
StreamGet = () => new Subject<IServiceMessage>(),
StartListening = () => { startListeningCall = true; }
};
mqShim.Instance.OpenConnection(true, true);
Assert.IsTrue(startListeningCall);
}
}
/// <summary>
/// Ensure that opening a connection with a Bad Queue Name will throw a proper
/// <see cref="ConfigurationErrorsException"/>.
/// </summary>
[TestMethod]
[ExpectedException(typeof(ConfigurationErrorsException))]
public void Ensure_OpenConnection_ThrowsBadQueueName()
{
const int nameReasonCode = 2085;
using (ShimsContext.Create())
{
ShimMQQueueManager.ConstructorStringHashtable = (_, __, ___) => { };
ShimMQQueueManager.AllInstances.AccessQueueStringInt32 = (_, __, ___) =>
{
throw new MQException(1, nameReasonCode);
};
var mqShim = new ShimMQMessageQueue
{
InstanceBehavior = ShimBehaviors.Fallthrough,
ConfigurationProviderGet = () => new ShimConfigurationProvider().Instance,
QueueNameGet = () => "something",
StreamGet = () => new Subject<IServiceMessage>(),
};
mqShim.Instance.OpenConnection();
}
}
/// <summary>
/// Ensure that any exception besides Bad Queue Name will be re-thrown
/// and bubble out of the OpenConnection method.
/// </summary>
[TestMethod]
[ExpectedException(typeof(MQException))]
public void Ensure_OpenConnection_ThrowsOthersExceptBadName()
{
using (ShimsContext.Create())
{
ShimMQQueueManager.ConstructorStringHashtable = (_, __, ___) => { };
ShimMQQueueManager.AllInstances.AccessQueueStringInt32 = (_, __, ___) =>
{
throw new MQException(1, 1);
};
var mqShim = new ShimMQMessageQueue
{
InstanceBehavior = ShimBehaviors.Fallthrough,
ConfigurationProviderGet = () => new ShimConfigurationProvider().Instance,
QueueNameGet = () => "something",
StreamGet = () => new Subject<IServiceMessage>(),
};
mqShim.Instance.OpenConnection();
}
}

view raw

gistfile1.cs

hosted with ❤ by GitHub

Recording a Web Performance test from a CodedUI test

On a project that’s well supported with tests, it is very common to have a good suite of automated tests. The two most common frameworks for test automation in the .Net stack are CodedUI and Watin. This article will cover utility code that improves recording a Web Performance test from a CodedUI test to automate the initial recording of the performance test. While it is possible to do the same with Watin, there is less control over the recording process, so I won’t cover Watin in this post.

There are two common tasks while going from a CodedUI into a Web Performance:

  • Find the Browser with the recorder.
  • Control the recording process. Often part of the CodedUI is getting to where we want to do the action, and this process isn’t part of the recording phase.

Finding a browser that is ready for recording

Finding a browser that is able to record is just going through the open browsers and look for the recording toolbar and the recording buttons. If we find them, then we have one and we can use it, otherwise just open a new browser and run the test normally.

Some things to note here:

  • Make sure that you wrap all the code that looks for recording controls in compiler directives. If the CodedUI is looking for these controls and can’t find them, it takes a lot longer to run, doing this as part of a build process will just increase the build time by a great amount.
  • While we are looking for things, keep track of the main buttons, Record and Resume, because we may want to click them later on, as part of scoping the recording process.
  • The method that launches the browser takes a Boolean parameter that allows the browser recorder to be paused at the start of the CodedUI test, instead of the default recording behavior.

The code that handles this:


public static class CodedUIExtensions
{
#if !DO_NOT_FIND_WEBRECORD
private static bool _recording;
private static WinButton _recordButton;
private static WinButton _pauseButton;
#endif
public static BrowserWindow Launch(bool pauseRecording = false)
{
return Launch("main.aspx", pauseRecording);
}
public static BrowserWindow Launch(string path, bool pauseRecording = false)
{
#if !DO_NOT_FIND_WEBRECORD
// Try to find an open browser that is recording to do a web performance recording session
try
{
var recordingBrowser = new BrowserWindow();
recordingBrowser.SearchProperties[UITestControl.PropertyNames.Name] = "Blank Page";
recordingBrowser.SearchProperties[UITestControl.PropertyNames.ClassName] = "IEFrame";
recordingBrowser.Find();
var recordWindow = new WinWindow(recordingBrowser);
recordWindow.SearchProperties[WinControl.PropertyNames.ControlName] = "toolStrip1";
recordWindow.Find();
var toolbar = new WinToolBar(recordWindow);
toolbar.SearchProperties[UITestControl.PropertyNames.Name] = "toolStrip1";
toolbar.Find();
_recordButton = new WinButton(toolbar);
_recordButton.SearchProperties[UITestControl.PropertyNames.Name] = "Record";
_recordButton.Find();
_pauseButton = new WinButton(toolbar);
_pauseButton.SearchProperties[UITestControl.PropertyNames.Name] = "Pause";
_pauseButton.Find();
if (pauseRecording)
{
Mouse.Click(_pauseButton);
recordingBrowser.WaitForControlReady();
}
recordingBrowser.NavigateToUrl(new Uri(path));
_recording = true;
return recordingBrowser;
}
catch
{
}
#endif
// A browser with a session ready to record couldn't be found, so open a new one
var browserWindow = BrowserWindow.Launch(path);
browserWindow.WaitForControlReady();
return browserWindow;
}
}

view raw

gistfile1.cs

hosted with ❤ by GitHub

Controlling the recording process

Besides finding the browser, that are 3 common things that we want, as part of controlling the recording process:

  • Be able to pause the recording process.
  • Be able to resume the recording process.
  • Some applications will spawn multiple windows, so at the end of the test an ALT+F4 is sent to the target app. However in the scope of recording a performance test, we want the browser to stay open, so we can do final adjustments or just stop recording and generate the test.

To accomplish this, just add 3 more methods to the utility class (also with compiler directives to improve test run speeds during builds):


public static void PauseRecording()
{
#if !DO_NOT_FIND_WEBRECORD
if (!_recording) return;
Mouse.Click(_pauseButton);
_pauseButton.WaitForControlReady();
#endif
}
public static void ResumeRecording()
{
#if !DO_NOT_FIND_WEBRECORD
if (!_recording) return;
Mouse.Click(_recordButton);
_recordButton.WaitForControlReady();
#endif
}
public static void CloseWindows()
{
#if !DO_NOT_FIND_WEBRECORD
if (!_recording)
{
Keyboard.SendKeys("%{F4}");
}
#else
Keyboard.SendKeys("%{F4}");
#endif
}

view raw

gistfile1.cs

hosted with ❤ by GitHub

Extending EF 4.x DbContext Generator to support Hashcode and Equality comparers

Currently I’m trying to fix a bunch of errors on a deep cloning template for EF 4.1 dbContext generated objects. This is done on a live database model, that’s fairly complex. One of the issues I had was the algorithm reaching a relation that it wasn’t supposed to be cloned, but later on, founding another relation where the same set of entities was supposed to be cloned, so I was left with relationships with the original entities that should be updated to the new cloned ones.

To fix this I had to keep track of what’s being cloned, so that in the end, I can run a “fixup” pass and update anything that’s referencing original entities that ended up being cloned later on. I came up with 2 ways to do this, either extend the objects and keep track of cloning information on a per object basis, or just track everything with a set of dictionaries during the process. Because many people in the team also work with these objects, and we have a junior guy, I didn’t want to pollute the objects with stuff that’s not business related, so I went with the dictionary approach.

The goal of this post isn’t to explain in detail how the template works, instead I just explain how to extend it. It contains my own flavor of code generation template syntax, that wasn’t born with T4, but with codesmith generation tools, and there I picked up a lot of habits that I still retain.

For the objects to be “Dictionary Ready” I implemented IEquatable, overrode GetHashCode() and Equals(object obj).

1.Getting a list of all the Primary Key properties in the entity

A good rule of thumb in all generation templates is to isolate all the different things you will work with in lists. The current template already isolates 3 things:

  • propertiesWithDefaultValues
  • collectionNavigationProperties
  • complexProperties
var propertiesWithDefaultValues = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity && p.DefaultValue != null);
var collectionNavigationProperties = entity.NavigationProperties.Where(np => np.DeclaringType == entity && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many);
var complexProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == entity);

However we need a 4th IEnumerable containing all the primary keys for the entity, so we need to extend the previous code with:

var keyProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity && ef.IsKey(p));
var propertiesWithDefaultValues = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity && p.DefaultValue != null);
var collectionNavigationProperties = entity.NavigationProperties.Where(np => np.DeclaringType == entity && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many);
var complexProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == entity);

2.Implementing IEquatable on the class header

Next the class header needs to be slightly changed to implement the IEquatable interface, but still retain the base class option from EF.

I replaced:

<#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#><#=code.StringBefore(" : ", code.Escape(entity.BaseType))#>

With:

<#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#><# if(entity.BaseType == null) { #> : IEquatable<<#=code.Escape(entity)#>><# } else { #> : <#=code.Escape(entity.BaseType)#>, IEquatable<<#=code.Escape(entity)#>><# } #>

3. Implementing IEquatable on the class body

At the end of the class, insert the implementation of Equals(EntityName other):

    public bool Equals(<#=code.Escape(entity)#> other)
    {
        if(other == null) return false;
        var result = true;
<#
	foreach(EdmProperty key in keyProperties)
	{
#>
        if(<#=code.Escape(key)#> != other.<#=code.Escape(key)#>) result = false;
<#
	}
#>
        return result;
    }

4.Overriding GetHashCode() and Equals(object)

For the finishing part, I overrode GetHashCode and Equals, also at the end of the class, with:

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 17;
<#
	foreach(EdmProperty key in keyProperties)
	{
#>
            hash = hash * 23 + <#=code.Escape(key)#>.GetHashCode();
<#
	}
#>
            return hash;
        }
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as <#=code.Escape(entity)#>);
    }

The GetHashCode implementation is a bit specific as it requires support for multiple keys. It is pulled from Joshua Bloch’s Effective Java. It is translated to C# and explained very well by Jon Skeet on Stackoverflow.

Creating a Notification button in WPF

Recently, I had to create a button that besides doing it’s normal job, would also show the amount of tasks that the User had to do inside that button.

To do this I decided to mimic the Notification button of popular Mobile Operating Systems do these days

ios_notifywp_notify

The end result was this:

notify

The full download of the solution can be found here

1.Button Framework

The button inherits from the WPF base button class, and is declared in a custom user control library, so the button style, that is not looked at in this post, is declared in the Generic.xaml file.

It implements a set of dependency properties to control the pooling for new Notifications, and the actual red circle showing the number is a WPF Adorner, so that it can overlap content on the visual tree and abstract the developer from the implications on the layout while using it.

To keep a clean WPF structure I implemented a fake delegate on a ViewModel that mimics our functionality of pooling a Web Service, this ViewModel is attached to the MainWindow, but in the real world we would have something like a menu bar and a menu bar ViewModel and these things would be implemented in those places.

The button usage is as follow:

<StackPanel VerticalAlignment="Center" Orientation="Vertical">
    <lib:NotificationButton Width="40"
                            Height="40"
                            NotifyFunc="{Binding NotifyDelegate}"
                            Poll="{Binding ElementName=PollCheck,
                                            Path=IsChecked}"
                            PollInterval="5">

        <TextBlock HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    FontSize="20"
                    FontWeight="Bold">
            R
        </TextBlock>

    </lib:NotificationButton>

    <CheckBox Name="PollCheck" IsChecked="True" />
</StackPanel>

2. Dependency Properties

The button exposes the following functionality:

  • NotifyFunc – The delegate of type Func<int> that gives you the Notification Number
  • Poll – True or False, tells the button whether to poll or not. Useful for scenarios where for example the button is hidden or collapsed and you want to stop polling.
  • PollInterval – In seconds, allows to configure the interval of the polling.

The implementation looks something like this:

#region Dependency Properties
#region PollInterval
public static readonly DependencyProperty PollIntervalProperty = DependencyProperty.Register(
    "PollInterval",
    typeof(Int32),
    typeof(NotificationButton),
    new UIPropertyMetadata(60) // default value for this DP
    );

public int PollInterval
{
    get { return (int)GetValue(PollIntervalProperty); }
    set { SetValue(PollIntervalProperty, value); }
}
#endregion

#region Poll
public static readonly DependencyProperty PollingProperty = DependencyProperty.Register(
    "Poll",
    typeof(Boolean),
    typeof(NotificationButton),
    new UIPropertyMetadata(true, OnPollChanged) // default value for this DP
    );

public bool Poll
{
    get { return (bool)GetValue(PollingProperty); }
    set { SetValue(PollingProperty, value); }
}

public void StartPolling()
{
    _timer.Change(PollInterval * 1000, PollInterval * 1000);
}

public void StopPolling()
{
    _timer.Change(Timeout.Infinite, Timeout.Infinite);
}

private static void OnPollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var nb = (NotificationButton)d;

    if ((bool)e.NewValue) nb.StartPolling();
    else nb.StopPolling();
}
#endregion

#region NotificationFunc
public static readonly DependencyProperty NotifyFuncProperty = DependencyProperty.Register(
    "NotifyFunc",
    typeof(Func<int>),
    typeof(NotificationButton)
    );

public Func<int> NotifyFunc
{
    get { return (Func<int>)GetValue(NotifyFuncProperty); }
    set { SetValue(NotifyFuncProperty, value); }
}
#endregion
#endregion

3.The Adorner

The Adorner is implemented on the same file as the button, because it is not shared by other controls, however you could isolate it on a different file to make it easier to reuse it.

The only specific thing is that I use the drawing context to draw direct primitives instead of instantiating WPF controls:

/// <summary>
/// The Notification adorner.
/// On Render implements direct drawing context calls.
/// </summary>
public class NotificationAdorder : Adorner
{
    public NotificationAdorder(UIElement adornedElement)
        : base(adornedElement)
    {
        DataContextChanged += NotificationAdorderDataContextChanged;
    }

    private void NotificationAdorderDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        InvalidateVisual();
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        if (DataContext == null) return; // Break if we don't have the Adorner databound

        var adornedElementRect = new Rect(AdornedElement.DesiredSize);
        var typeFace = new Typeface(new FontFamily("Courier New"), FontStyles.Normal, FontWeights.ExtraBold,
                                    FontStretches.Condensed);

        var text = new FormattedText(
            DataContext.ToString(),
            CultureInfo.GetCultureInfo("en-us"),
            FlowDirection.RightToLeft,
            typeFace,
            16, Brushes.White
            );

        var pointOfOrigin = new Point
                                {
                                    X = adornedElementRect.BottomRight.X,
                                    Y = adornedElementRect.BottomRight.Y - text.Height * 0.7
                                };

        var elipseCenter = new Point
                                {
                                    X = pointOfOrigin.X - text.Width / 2,
                                    Y = pointOfOrigin.Y + text.Height / 2
                                };

        var elipseBrush = new SolidColorBrush
                                {
                                    Color = Colors.DarkRed,
                                    Opacity = 0.8
                                };

        drawingContext.DrawEllipse(
            elipseBrush,
            new Pen(Brushes.White, 2),
            elipseCenter,
            text.Width * 0.9,
            text.Height * 0.5
            );

        drawingContext.DrawText(text, pointOfOrigin);
    }
}

The adorner is attached to the button on the Loaded delegate

var adornerLayler = AdornerLayer.GetAdornerLayer(this);
_adorner = new NotificationAdorder(this) {DataContext = null};
adornerLayler.Add(_adorner);

Of note is also the fact that we need to capture the datacontext changed even, so that we can call the InvalidateVisual to force WPF to redraw the Adorner.

4.Other Parts of interest

It is important to never block the WPF UI thread of calls to Web Services, to accomplish this I used a bit of TPL code to first get some dependency properties in the UI thread, then call the Web Service in a separate thread, and finally rebind the data in the UI thread:

/// <summary>
/// Delegates the fake Web Service call onto a different thread, while retaining the UI Thread to update the UI
/// </summary>
/// <param name="state"></param>
private void CheckContent(object state = null)
{
    int? delegateReturn = 0;
    Func<int> func = null;

    Task.Factory.StartNew(() =>
                                {
                                    func = NotifyFunc;
                                }
        , new CancellationToken(), TaskCreationOptions.None, _uiContext)
        .ContinueWith(t =>
                            {
                                delegateReturn = func();
                                if (delegateReturn < 1) delegateReturn = null; // Normalize to not show if not at least 1
                            }
        )
        .ContinueWith(t =>
                        {
                            _adorner.DataContext = delegateReturn;
                        }
        , new CancellationToken(), TaskContinuationOptions.None, _uiContext);
}

To control the pooling I used a System.Threading.Timer that is created on the Loaded delegate:

_timer = new Timer(CheckContent, null, Timeout.Infinite, Timeout.Infinite);
if (Poll) _timer.Change(PollInterval * 1000, PollInterval * 1000);

And controlled by these 2 utility methods:

public void StartPolling()
{
    _timer.Change(PollInterval * 1000, PollInterval * 1000);
}

public void StopPolling()
{
    _timer.Change(Timeout.Infinite, Timeout.Infinite);
}

5.The ViewModel

It is a very simple ViewModel, that basically declared and implements the Function delegate:

/// <summary>
/// The view model, with a fake implementation that calls a 1 sec sleep to make sure the UI is never blocked.
/// </summary>
public class NotificationViewModel
{
    public NotificationViewModel()
    {
        NotifyDelegate = NotificationImplementation;
    }

    public Func<int> NotifyDelegate { get; set; }

    private static int NotificationImplementation()
    {
        var r = new Random();
        Thread.Sleep(1000);
        return r.Next(1, 99);
    }
}