Monday, October 8, 2012

.NET Async Utility

Below is a simple C# class that I've used on many projects over the years for fire-and-forget type operations. For example, if you have a data collection service that pools multiple sources for information, you probably do not want to wait for the first remote call to finish before moving on to the next. This utility can be used to simply move that operation on to another thread to be executed.

The one caveat to keep in mind is that, in cases of exceptions, the onError action gets executed on a different thread than the original caller. This means that you need to be careful to synchronize your threads before changing GUI controls.


using System.IO;
using System.Threading;
public static class AsyncUtil
{
 private static readonly log4net.ILog _log = 
  log4net.LogManager.GetLogger(typeof(AsyncUtil));
 
 /// <summary>
 /// This is a fire-and-forget type execution...
 /// </summary>
 /// <param name="action">
 /// The action method that you want to run asynchronously.
 /// </param>
 /// <param name="onError">
 /// The action method that you want to run after an exception.
 /// </param>
 public static void AsyncExecute(Action action, 
  Action<ErrorEventArgs> onError)
 {
  ThreadPool.QueueUserWorkItem(item =>
   {
   try
   {
    action();
   }
   catch(Exception ex)
   {
    _log.Error(ex);
    if(onError!=null)
    {
     var args = new ErrorEventArgs(ex);
     onError(args);
    }
   }
   });
 }
}

Wednesday, February 16, 2011

Simple ListBox Validator

I ran into a situation today where I was copying values from a TextBox to a ListBox and before submitting the form, I needed to validate that there were actually values in the ListBox. Sounds simple enough, right? At first I tried using a RequiredFieldValidator and it seemed to work. But, I was able to get the form into a state where it was incorrectly flagging the ListBox value as invalid. Here is a simple ListBox validator that I wrote for this situation.

using System.Web.UI.WebControls;
public class ListBoxRequiredFieldValidator : CustomValidator
{
    public ListBoxRequiredFieldValidator()
    {
        EnableClientScript = true;
        ValidateEmptyText = true;
    }

    protected override void OnPreRender(EventArgs e)
    {
        ClientValidationFunction = 
                string.Concat(ClientID, "_ValidateRequiredListBox");
        base.OnPreRender(e);
        string validatedcontrolclientid = 
                GetControlRenderID(ControlToValidate);
        const string scriptFormat =
            @"";

        var script = string.Format(scriptFormat,
                                    ClientID,
                                    validatedcontrolclientid);
        Page.ClientScript.RegisterClientScriptBlock(this.GetType(), 
                string.Concat(ClientID, "_ValidationScript"), script);
    }
}

Wednesday, December 15, 2010

Log4Net Appender for Displaying Messages on a Windows Form Application

Yesterday, I ran into a situation where I needed to display logging information on a WinForm application. The API that I wanted to show logging for was already using log4net for all of its logging, so the simplest way to accomplish my goal was to implement a custom log4net appender. The code below was the minimum that I needed, but there is room for enhancements as noted in the comments.

using System;
using System.Windows.Forms;
using log4net;
using log4net.Appender;
using log4net.Repository.Hierarchy;
public class TextBoxAppender : IAppender
{
    private TextBox _textBox;
    private readonly object _lockObj = new object();

    public TextBoxAppender(TextBox textBox)
    {
        var frm = textBox.FindForm();
        if(frm==null)
            return;

        frm.FormClosing += delegate { Close(); };

        _textBox = textBox;
        Name = "TextBoxAppender";
    }

    public string Name { get; set; }

    public static void ConfigureTextBoxAppender(TextBox textBox)
    {
        var hierarchy = (Hierarchy)LogManager.GetRepository();
        var appender = new TextBoxAppender(textBox);
        hierarchy.Root.AddAppender(appender);
    }

    public void Close()
    {
        try
        {
            // This locking is required to avoid null reference exceptions
            // in situations where DoAppend() is writing to the TextBox while
            // Close() is nulling out the TextBox.
            lock (_lockObj)
            {
                _textBox = null;
            }

            var hierarchy = (Hierarchy)LogManager.GetRepository();
            hierarchy.Root.RemoveAppender(this);
        }
        catch
        {
            // There is not much that can be done here, and
            // swallowing the error is desired in my situation.
        }
    }

    public void DoAppend(log4net.Core.LoggingEvent loggingEvent)
    {
        try
        {
            if (_textBox == null)
                return;

            // For my situation, this quick and dirt filter was all that was 
            // needed. Depending on your situation, you may decide to delete 
            // this logic, modify it slightly, or implement something a 
            // little more sophisticated.
            if(loggingEvent.LoggerName.Contains("NHibernate"))
                return;

            // Again, my requirements were simple; displaying the message was
            // all that was needed. Depending on your circumstances, you may
            // decide to add information to the displayed message 
            // (e.g. log level) or implement something a little more 
            // dynamic.
            var msg = string.Concat(loggingEvent.RenderedMessage, "\r\n");

            lock (_lockObj)
            {
                // This check is required a second time because this class 
                // is executing on multiple threads.
                if (_textBox == null)
                    return;

                // Because the logging is running on a different thread than
                // the GUI, the control's "BeginInvoke" method has to be
                // leveraged in order to append the message. Otherwise, a 
                // threading exception will be thrown. 
                var del = new Action<string>(s => _textBox.AppendText(s));
                _textBox.BeginInvoke(del, msg);
            }
        }
        catch
        {
            // There is not much that can be done here, and
            // swallowing the error is desired in my situation.
        }
    }
}


To wirer this appender up to a TextBox, simply use the following code.
//Where "LoggingTextBox" is a TextBox having the following settings:
//LoggingTextBox.Multiline = true;
//LoggingTextBox.ReadOnly = true;
//LoggingTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;

TextBoxAppender.ConfigureTextBoxAppender(LoggingTextBox);

Wednesday, December 8, 2010

Ignoring XPath Namespaces

XML namespaces might be useful for resolving conflicts when combining segments from multiple XML entitied into a single file. They can also be extremely useful for versioning large complicated documents. But, to most developers who are merely trying to accomplish simple tasks in a short amount of time, they are nothing more than obstacles.

It is still common to see code that uses XmlNamespaceManager syntax when trying to adjust for namespaces. I have always felt that this syntax was overkill and overly complicated for everyday situations. It is also hard to remember, so there is a lot of copy-and-paste inheritance. Worst of all, it does not work for nearly identical documents that do not include the namespace.
public XmlNodeList GetProjectReferences(XmlDocument xml)
{
 var nsMgr = new XmlNamespaceManager(xml.NameTable);
 nsMgr.AddNamespace("ns", 
  "http://schemas.microsoft.com/developer/msbuild/2003");
 var nodes = xml.SelectNodes("//ns:ProjectReference/@Include", 
  nsMgr);
 return nodes;
}


A simpler way of handling this problem is to modify the syntax of the XPaths themselves. For example, the following code accomplishes the same return for documents containing namespaces, but it still works on similar xml where the namespaces are excluded. I also feel that it is much easier to remember.
public XmlNodeList GetProjectReferences(XmlDocument xml)
{
 var nodes = xml.SelectNodes("//*[local-name()='ProjectReference']/@Include");
 return nodes;
}

Monday, October 25, 2010

Writing an SSRS Validation Tool

I have been involved in a project that integrates with the Microsoft SQL Server Reporting Services (SSRS) web service API for quite a while now, and the majority of the issues I have seen are related to the configuration of SSRS and the installation of our product on top of SSRS.

One of the first and most painful experiences my team had was configuring versions of SSRS prior to SQL Server 2005 SP2. It was extremely temperamental to configure, and I would strongly recommend not supporting earlier versions. However, since main stream support for SQL Server 2005 SP2 has already ended, you will probably want to support something more modern such as SQL Server 2008 R2. If you are installing your software in hundreds of customer sites, your installer is going to need a mechanism to verify that the SSRS instance you are given meets your minimum version requirement.

Installing the correct version of SSRS can be trickier than you think. This difficulty has to do with the overall adoption of SSRS. I currently work in the health care sector, and in my experience, very few hospitals know what SSRS does and most of them do not use it. Consequently, DBAs often have the Data Engine and Sql Agent features of SQL Server installed and patched, but none of the other features get installed. When the DBA installs SSRS on to the existing server, they will often forget to reapply the service packs. Therefore, the versions of SSRS and the Data Engine do not match (i.e. the Data Engine is patched, but the SSRS is not). This will not only cause odd behavior, but it masks the fact that the server is not running the minimum specified version of SSRS.

Verifying the version of SSRS is not straight forward either. It is highly unlikely that a DBA would let you install anything directly on to a data server. Therefore, your application is likely to be installed on a separate machine. This means that the installer will not have access to the registry or file system on the machine that houses SSRS, and will not be able to perform the actions described on TechNet to detect the version. Because of this, the easiest way I have found to check the version is to write a command line tool that does a web request to the SSRS web service API virtual directory (e.g. http://SomeServer/ReportServer) and verify the version number returned in the HTTP response.



The first thing that has to happen to verify the SSRS version via a web request is to authenticate. Coincidentally, the second major issue my project has run into is confusion over the credentials for the service account we use to communicate with the SSRS APIs. Despite excellent documentation, the person running the installer is likely to be confused about why the installer needs credentials for a windows account, what the scope of that account should be (i.e. does it need to be a domain account or can it be local to the database server), and where to configure this user to have adequate permissions in SSRS. If you are simply installing to an intranet data warehouse, this might not be as big of an issue because installations are rare and handled by knowledgeable staff. However, if your company produces software that is installed at customer sites and the installation depends on a variety of people who may or may not be knowledgeable, it is extremely important that your installer be able to validate the version of SSRS and verify that the service user can authenticate.

Since, by default, SSRS uses windows integrated security within IIS, the web request to verify the version number has to be configured with NT Lan Management (NTLM) security.

const string path = "http://SomeServer/ReportServer";
var uri = new Uri(path);
var nCreds = new NetworkCredential("MyUsername", "MyPassword", "MyDomain");
var creds = new CredentialCache { { uri, "NTLM", nCreds}};
var req = (HttpWebRequest) WebRequest.Create(path);
req.Credentials = creds;


Once the credentials are configured, the response stream can be read and iterated through.

using (var strm = req.GetResponse().GetResponseStream())
{
if (strm == null)
throw new NullReferenceException("Response stream was null.");

using (var stream = new StreamReader(strm))
{
var line = stream.ReadLine();
while (!stream.EndOfStream)
{
//TODO: Add comparison logic here...

line = stream.ReadLine();
}
}
}


As each line is read from the response stream, a regular expression can be used to identify the version number and it can be compared to a constant.

var minVersion = new Version(9, 00, 4053, 00);
const string regex = "^[\\s]*?<meta[\\s]*?name=\"Generator\"[\\s]*?content=\"" +
"Microsoft[\\s]*?SQL[\\s]*?Server[\\s]*?Reporting[\\s]*?Services[\\s]*?" +
"Version[\\s]*?([0-9]+?\\.[0-9]+?\\.[0-9]+?\\.[0-9]+?)\">$";
const RegexOptions options = ((RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) | RegexOptions.IgnoreCase);
var reg = new Regex(regex, options);

if (!string.IsNullOrEmpty(line) && reg.IsMatch(line))
{
var match = reg.Match(line);
var versionString = match.Groups[1].Value;
var version = new Version(versionString);

if (version >= minVersion)
return true;
}


To make this tool more useful to the end user and to help them diagnose their problems, more granular return codes can be used instead of using a boolean return. Typically on projects I have been involved with, a negative return code signifies an error and anything greater or equal to zero is a success. With the use of return codes, a series of catch blocks can be used to check for common errors. (Note: For simplicity, the examples in this post do not have logging. However, logging is also extremely useful to the users when diagnosing a problem, and it should not be forgotten.)

catch (WebException ex)
{
if (ex.Message.Contains("(401) Unauthorized."))
return -3;
if (ex.Message.Contains("(404) Not Found."))
return -4;

return -5; //unknown error
}
catch (Exception ex)
{
return -5; //unknown error
}


Verifying your software's dependencies is an important practice that can eliminate problems and embarrassment when your product is deployed. Putting all of the logic from this article together, a method to validate the SSRS version and the service credentials might look something like the following.

//Add the following references:
//using System;
//using System.IO;
//using System.Net;
//using System.Text.RegularExpressions;

public int VerifyMinimumSsrsVerion(string url, string domain, string un, string pwd)
{
var minVersion = new Version(9, 00, 4053, 00);
const string regex = "^[\\s]*?<meta[\\s]*?name=\"Generator\"[\\s]*?content=\"" +
"Microsoft[\\s]*?SQL[\\s]*?Server[\\s]*?Reporting[\\s]*?Services[\\s]*?" +
"Version[\\s]*?([0-9]+?\\.[0-9]+?\\.[0-9]+?\\.[0-9]+?)\">$";
const RegexOptions options = ((RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) | RegexOptions.IgnoreCase);
var reg = new Regex(regex, options);

try
{
var nCreds = new NetworkCredential(un, pwd, domain);
var creds = new CredentialCache { { new Uri(url), "NTLM", nCreds}};
var req = (HttpWebRequest) WebRequest.Create(url);
req.Credentials = creds;

using (var strm = req.GetResponse().GetResponseStream())
{
if (strm == null)
throw new NullReferenceException("Response stream was null.");

using (var stream = new StreamReader(strm))
{
var line = stream.ReadLine();
while (!stream.EndOfStream)
{
if (!string.IsNullOrEmpty(line) && reg.IsMatch(line))
{
var match = reg.Match(line);
var versionString = match.Groups[1].Value;
var version = new Version(versionString);

if (version >= minVersion)
return 0; //sucess
else
return -1; //Version did not meet minimum
}

line = stream.ReadLine();
}
return -2; //Version number could not be identified.  
}
}
}
catch (WebException ex)
{
if (ex.Message.Contains("(401) Unauthorized."))
return -3;
if (ex.Message.Contains("(404) Not Found."))
return -4;

return -5; //unknown error
}
catch (Exception)
{
return -5; //unknown error
}
}

Thursday, October 21, 2010

Retry Utility

This morning I ran into a situation where I needed to retry several method calls if they failed. I decided that the easiest and cleanest way to accomplish this would be via a generic utility class. Below is the class I wrote. In the future I may add a method that will handle targets with void returns. But, for now, this is all my application required.

public class RetryUtil
{
private static readonly log4net.ILog _log = log4net.LogManager.GetLogger(typeof(RetryUtil));

/// <summary>
/// Executes the specified function.
/// </summary>
/// <typeparam name="T">Type that the target funtion returns.</typeparam>
/// <param name="func">The target function.</param>
/// <param name="requiresRetry">Function that validates whether a retry is required based on the target function's output.</param>
/// <param name="retryCount">The maximum number of times the target function should be executed.</param>
/// <param name="sleepSeconds">The number of seconds to sleep the thread between retries.</param>
/// <returns>The result of the target function.</returns>
public T Execute<T>(Func<T> func, Func<T, bool> requiresRetry, int retryCount, int sleepSeconds)
{
var attempt = 0;
while (attempt < retryCount)
{
try
{
_log.InfoFormat("Attempting call {0} of {1}", attempt + 1, retryCount);
var t = func();

if (requiresRetry(t))
{
attempt++;
if (attempt >= retryCount)
return t;

_log.WarnFormat("Target method returned {0}... Retrying...", t);

if (sleepSeconds > 0)
{
_log.InfoFormat("Sleeping thread for {0} seconds.", sleepSeconds);
Thread.Sleep(TimeSpan.FromSeconds(sleepSeconds));
}
continue;
}

return t;
}
catch (Exception ex)
{
attempt++;
_log.Error(ex);

if (attempt >= retryCount)
throw;
}
}
return default(T);
}
}


To call this utility, simply pass in a delegate (or lambda expression) that wraps your target method, a delegate (or lambda expression) that validates the return, a retry count, and the number of seconds you want to sleep the thread between retries.

public int TargetMethod(int foo)
{
//Do work..
return -1;
}

public void CallingMethod()
{
var retryUtil = new RetryUtil();

//Example call using delegates
Func<int> target = delegate { return MyTargetMethod(123); };
Func<int, bool> validate = delegate(int foo) { return foo < 0; };
var result1 = retryUtil.Execute(target, validate, 5, 10);

//Example using lambda expressions
var result2 = retryUtil.Execute(() => MyTargetMethod(123), (i=> i < 0), 5, 10);
}

Tuesday, April 20, 2010

WCF Serialization Basics - Opt In

This post is part of a series of posts that I am writing as I prepare for a presentation on WCF basics.

Prior to WCF, when exposing a web service, serialization was done using the SoapFormatter class. Using the SoapFormatter, the developer would tag the class being serialized with the Serializable attribute, and the SoapFormatter would serialize all of the fields in the class, regardless of visibility, unless you opted out by assigning the NonSerialized attribute to a field that you wanted to excluded.


//Add reference to:
//System.Runtime.Serialization.Formatters.Soap.dll

using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;

[Serializable]
public class Person
{
//Note: Cannot assign this to a property.
//Must use field back property
[NonSerializedAttribute]
private string _lastname;

public int ID {get;set;}

public string FirstName {get;set;}
public string LastName
{
get {return _lastname;}
set {_lastname = value;}
}
}

public class TestApp
{
public static void Main()
{
try
{
var person = new Person();
person.ID = 1;
person.FirstName = "Fred";
person.LastName = "Flintstone";


using(var memStrm = new MemoryStream())
{
IFormatter formatter =
new SoapFormatter();
formatter.Serialize(memStrm, person);

var data = new byte[memStrm.Length];
Array.Copy(memStrm.GetBuffer(),
data, data.Length);
var text =
Encoding.UTF8.GetString(data);
Console.WriteLine(text);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
Console.Write("Press any key...");
Console.ReadKey();
}
}
}




As you can see in the output above, the _lastname field was not serialized by the SoapFormatter because it was tagged with the NonSerialized attribute.

One of the problems with the SoapFormatter's opt-out approach is that every time you add a field to a class that is serializable, you have to consider whether or not the new field is serializable. If it is not, you will not get an error until run-time. The developer also has to remember that when the a new auto-implemented property is added to a class, the compiler adds fields to the class behind the scenes. This is true for both the "ID" and "FirstName" properties in the example above as is evident in the long, awkward xml node names that end with "BackingField."

To get around this, WFC's DataContractSerializer follows an opt-in approach. With the DataContractSerializer, the developer tags the class being serialized with the DataContract attribute, and then tags the fields and/or attributes that should be serialized with the DataMember attribute. Only the fields and/or properties that were tagged with the DataMember attribute will be included in the serialized stream.


//Add reference to System.Runtime.Serialization.dll

using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;

[DataContract]
public class Person
{
//demonstrates serialization of a field
[DataMember]
private string _firstName;

//demonstrates serialization of a property
[DataMember]
public int ID {get;set;}

public string FirstName
{
get {return _firstName;}   
set {_firstName = value;}
}

//demonstrates data that was not serialized
public string LastName {get;set;}
}

public class TestApp
{
public static void Main()
{
try
{
var person = new Person();
person.ID = 1;
person.FirstName = "Fred";
person.LastName = "Flintstone";


using(var memStrm = new MemoryStream())
{
var pType = person.GetType();
var serializer =
new DataContractSerializer(pType);
serializer
.WriteObject(memStrm, person);

var data = new byte[memStrm.Length];
Array.Copy(memStrm.GetBuffer(),
data, data.Length);
var text =
Encoding.UTF8.GetString(data);
Console.WriteLine(text);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
Console.Write("Press any key...");
Console.ReadKey();
}
}
}



As you can see in the above example, the LastName property was not serialized because it did not have the DataMember attribute. Also notice that the "ID" property was serialized at the property level, but the first name was serialized at the field name.



WCF added the flexibility to serialize not only at the field level, but also at the property level. This flexibility adds a lot of power, but it can also lead to unexpected results. Be careful not to add the DataMember attribute to both the property and its backing field. In this situation, both will be serialized. Not only does this clutter your data contract and add unnecessary traffic over the wire, but it also can lead to weird behavior or an error.



WCF's opt-in approach also helps immensely in practice because it complies with the third tenet of Service Oriented Architecture that states "Services share schema and contract, not class." When you chose to add the DataMember attribute to a member of a DataContract class, you are choosing to change the contract. This was not the case when you decided to add a private field to a class marked Serializable.