Rory Primrose

Learn from my mistakes, you don't have time to make them yourself

View project on GitHub

Testing IErrorHandler

I have previously posted (here, here and here) about using IErrorHandler to provide error handling and exception shielding in WCF services. What I haven’t discussed is how to test an implementation of this interface.

The reason for posting this is that I recently found that I had a bug in a service where un-handled exceptions weren’t being shielded from clients. This was purely because my unit tests were not validating the messages being generated for clients by the error handler.

The following method came about after a bit of research (mainly from here) and playing with code to make the solution work and easy to use. This method will assist unit testing the output of ProvideFault as it provides an easy way to extract a Fault from a Message returned by the ProvideFault method. This fault can then be tested for expected outcomes of the unit test.

Read More

Splitting up arguments with a regular expression

There have been several times when I have needed to process a string that contains a set of arguments. It always seems to be a lot of work splitting up arguments by using white space as a delimiter because you need to take into account white space that is surrounded by brackets.

Just for kicks, I tried to come up with a regular expression that would do just that. Here is the result.

Read More

SQLEXPRESS fails to start

I have just encountered a problem where the SQLEXPRESS instance installed on my machine was not starting. It looks like a recent windows update has failed, but also knocked out SQL Server. The event log contains the following entry:

Error 3(error not found) occurred while opening file ‘C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\DATA\master.mdf’ to obtain configuration information at startup. An invalid startup option might have caused the error. Verify your startup options, and correct or remove them if necessary.

After searching around, there seems to be lots of forum posts going back several years about this issue. The problem is that the only known solution seems to be to change the credentials of the SQLEXPRESS service account to Local System. This will then allow the service to start. Doing this through the services console presents a problem however because you can’t set the service credentials back to Network Service as you need to know the password.

Read More

Troubleshooting DataDude deployment with TeamBuild

I’m working through the best way of getting DataDude to build and deploy a database using TeamBuild. When I kicked off a build, the build script failed with the following error:

Task "SqlBuildTask"   
  Building deployment script for [DatabaseName] : AlwaysCreateNewDatabase, EnableFullTextSearch, BlockIncrementalDeploymentIfDataLoss   
MSBUILD : Build error TSD158: Cannot open user default database. Login failed.   
MSBUILD : Build error TSD158: Login failed for user '[TeamBuildUserName]'.   
Done executing task "SqlBuildTask" -- FAILED.
Read More

Guidance on use of include in XML documentation comments

I have previously posted about using the include element for my XML documentation in cases where there is duplicated content. After a recent code review, the reviewer commented that the include element made it difficult to read the documentation because large parts of the XML documentation were abstracted out to an XML file. This made me look at ways around this and the affect of the include tag had on the tooling support.

As a quick overview, the include element in XML documentation tells the compiler to go to the specified XML file and run an XPath query (recursively). It pulls in the result of that XPath query and injects the content into the XML documentation being generated for a code element.

Read More

Tracing Performance Tips

I have recently been working with tracing performance and have posted several tidbits of information. Here is the overview.

  1. Use TraceSource instead of Trace
  2. Disable global locking
  3. Clear the default listener in configuration
  4. Don’t collect stacktrace information if not required
  5. Create TraceSource instances once per name and cache for reuse. I have encountered memory leaks from creating large numbers of instances of the same TraceSource name.
  6. Create a unique TraceSource and TraceListener for each logical part/tier/layer of the application (locking performance and data segregation)
  7. Use thread safe listeners if possible
  8. Check TraceSource.Switch.ShouldTrace before calculating any expensive information to provide to the trace message

On a side note, don’t forget to turn off code coverage for running load tests.

Read More

Don't trace the callstack if you don't need to

Here is another performance tip with tracing. In configuration, there is the opportunity to define some tracing options. These options determine the actions taken by TraceListener when it writes the footer of the trace record for a given message. One of the options is to output the Callstack.

It takes a bit of work to calculate the callstack. If you don’t need that information, then don’t configure your listeners to calculate it.

To demonstrate the difference, I created two load tests that each ran a unit test that used its own specific TraceSource. The reason for two separate load tests was to avoid a locking issue that would impact the results.

Here is the configuration I used:

Read More

Carrying tracing weight you didn't know you had

Continuing on my performance testing of tracing components, there is another factor I realised that may be impacting the performance I get out of my code.

When the TraceSource.Listeners property is referenced, the collection is initialised using the application configuration. Regardless of whether there is a TraceSource configured for the provided name or what listeners are defined, there is always a default listener that is added to the configured collection of listeners. This is the System.Diagnostics.DefaultTraceListener.

All the tracing methods of this listener implementation call down to an internalWrite method that has the following implementation:

Read More