C# Generic Type and Aliased Type to string

C# code, that uses reflection, for translating a type to a pretty class name. Solving the problem that Type.Name returns a really ugly string:

  • typeof(int?).ToString() = System.Nullable`1[System.Int32]
  • typeof(List<string>).ToString() = System.Collections.Generic.List`1[System.String]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IdentityAudit.Utilities
{
    public static class TypePrettyName
    {
        public static bool IsSubclassOfRawGeneric(Type generic, Type toCheck)
        {
            while (toCheck != typeof(object) && toCheck != null)
            {
                var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
                if (generic == cur)
                {
                    return true;
                }
                toCheck = toCheck.BaseType;
            }
            return false;
        }

        public static string GetTypePrettyName(Type type)
        {
            if (type.IsGenericType)
            {
                if (IsSubclassOfRawGeneric(typeof(Nullable<>), type))
                {
                    return GetTypePrettyName(type.GetGenericArguments()[0]) + "?";
                }

                string typeName = type.Name.Remove(type.Name.IndexOf('`'));
                string args =
                    string.Join(
                        ",",
                        type.GetGenericArguments().Select(arg => GetTypePrettyName(arg)));
                return typeName + "            }
            else
            {
                return SimpleTypeNameUseAlias(type);
            }
        }

        public static string SimpleTypeNameUseAlias(Type type)
        {
            switch (type.Name)
            {
                case "String": return "string";
                case "Object": return "object";
                case "Boolean": return "bool";
                case "Byte": return "bool";
                case "SByte": return "sbyte";
                case "Int16": return "short";
                case "UInt16": return "ushort";
                case "Int32": return "int";
                case "UInt32": return "uint";
                case "Int64": return "long";
                case "UInt64": return "ulong";
                case "Single": return "float";
                case "Double": return "double";
                case "Decimal": return "decimal";
                case "Char": return "char";
                default:
                    return type.Name;
            }
        }
    }
}

How to publish a Microsoft MVC app in a WordPress blog (in IIS7)

If you have a wordpress blog and you wish to publish an MVC application (or probably any other kind of asp application) as a sub-directory of the blog, this post will describe how to do it.

This post assumes that

  • You have a WordPress site hosted on a computer you control
  • The WordPress site is hosted on a iis7
  • You wish to add the MVC app as a subdirectory to the blog
    If you wish to host the blog inside the app instead of the other way around – then this post isn’t for you.

Set your application to appear in a virtual directory

First, make sure that your MVC expects to be placed in a virtual directory. This doesn’t make the application deploy into a virtual directory (that’s the next step), but it makes your application use “/Verktyg” in all it’s urls.

    • Select the project
    • Select properties
    • Select the “Web” tab
    • Enter the name of the virtual path in the appropriate box – in this case it’s called “/Verktyg” (which means “Tools” in swedish)
    • Test your application, make sure all your links still work.

image

Make your application deploy to a virtual path

Now you tell your application where on the IIS to deploy – both the web site and the virtual directory.

  • Select the project
  • Select properties
  • Select the “Package/Publish Web” tab
  • Enter the name of the site and the virtual path
    image
  • Hit save

Build a deployment package

  • Select the project
  • Right-click on the project
  • Select the menu option “Build deployment package”
  • Copy the deployment package to the server hosting the IIS 7 server

Configure Web.config on the WordPress site

You must configure the Web.config file of the blog to ignore anything that’s intended for the MVC application.

      By default, the Web.config file of the wordpress site is inherited by the MVC application – that’s something that we don’t want – and that’s fixed by adding a

location

      tag inside the configuration tag. The location tag must have the attribute “

inheritInChildApplications

      ” to false.
<configuration>
	<location inheritInChildApplications="false">
		<system.webServer>
			<rewrite>
				<rules>
					<rule name="wordpress" patternSyntax="Wildcard">
						<match url="*" negate="false" />
							<conditions>
							<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
							<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
							</conditions>
						<action type="Rewrite" url="index.php" />
					</rule>
				</rules>
			</rewrite>
		</system.webServer>
	</location>
</configuration>

So locate your Web.config file – it’s stored in the same directory as the site;

image

And add the location tag. Remember to include the closing tag.

Create and configure Virtual path on WordPress site

Before we can install the app, we must make sure that IIS7 has the appropriate Virtual Path (called Verktyg in our example) and that the correct application pool is serving the requests.

  • Create a directory for the virtual path
  • Open “Internet Information Services (IIS) Manager”
  • Select the site;image
  • Right-click on the site and select “Add application”image
  • Make sure that the application pool you select  uses .NET framework 4.
  • Press ok

Install the application

Now it’s time to install the application. As you copied the installation package in one of the previous steps, you should have a directory on the IIS machine that looks something like this;

image

Running “Seo.deploy.cmd” will install the application – I usually use the /y flag to skip the questions. Actually, for deployment convenience, I typically create two .bat files, one for copying the deployment package from the development machine and one for deploying the new code. That way I can quickly update the application.

image

1.copy.bat (relies on the fact that I’m using Remote Desktop to access the web server and that I’m sharing my local drives with the web server):

xcopy \\tsclient\C\Dev\Seo\Seo.Web\obj\Debug\Package\*.* package /D /Y

2.install.bat

package\Seo.Web.deploy.cmd /y

Start cmd as Administrator by right-clicking (in the start menu) and selecting “Run as administrator”

image

Go to the directory where you’ve stored the batch files described above and press “1” and tab – the shell will automatically suggest the 1.copy.bat file;

image

Press 2 and tab – the shell will automatically suggest the “2.install.bat” – it should look something like this;

image

If installation fails with the message below “Site ‘Default Web Site’ does not exist” then you’ve failed with the step called “Make your application deploy to a virtual path”. Make sure to build and copy a new deployment package.

image

Visit the site

You should now be able to visit the site; like this Tools for SEO optimizing – in Swedish.

C# Reflection AttributeHelper

AttributeHelper is a collection of methods I’ve developed to help me retrieve Attribute information for Types and methods in C# (through Reflection). I’m publishing it on my blog because it’s too small to create a CodePlex project for and it’s something I want access to from wherever I am. If you find use for it too, then thats great.

It uses caching of attributes to speed up access, because retrieving type information is typically quite time consuming. For caching it uses a trivial Dictionary.

Here’s the code;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;

namespace IdentityAudit.Utilities
{
    public static class AttributeHelper
    {
        private static Dictionary<object, List<Attribute>> _attributeCache = new Dictionary<object, List<Attribute>>();

        public static Dictionary<object, List<Attribute>> AttributeCache { get { return _attributeCache; } }

        // Types
        public static List<Attribute> GetTypeAttributes<TType>()
        {
            return GetTypeAttributes(typeof(TType));
        }

        public static List<Attribute> GetTypeAttributes(Type type)
        {
            return LockAndGetAttributes(type, tp => ((Type)tp).GetCustomAttributes(true));
        }

        public static List<TAttributeType> GetTypeAttributes<TAttributeType>(Type type, Func<TAttributeType, bool> predicate = null)
        {
            return
                GetTypeAttributes(type)
                    .Where<Attribute, TAttributeType>()
                    .Where(attr => predicate == null || predicate(attr))
                    .ToList();
        }

        public static List<TAttributeType> GetTypeAttributes<TType, TAttributeType>(Func<TAttributeType, bool> predicate = null)
        {
            return GetTypeAttributes(typeof(TType), predicate);
        }

        public static TAttributeType GetTypeAttribute<TType, TAttributeType>(Func<TAttributeType, bool> predicate = null)
        {
            return
                GetTypeAttribute(typeof(TType), predicate);
        }

        public static TAttributeType GetTypeAttribute<TAttributeType>(Type type, Func<TAttributeType, bool> predicate = null)
        {
            return
                GetTypeAttributes<TAttributeType>(type, predicate)
                    .FirstOrDefault();
        }

        public static bool HasTypeAttribute<TType, TAttributeType>(Func<TAttributeType, bool> predicate = null)
        {
            return HasTypeAttribute<TAttributeType>(typeof(TType), predicate);
        }

        public static bool HasTypeAttribute<TAttributeType>(Type type, Func<TAttributeType, bool> predicate = null)
        {
            return GetTypeAttribute<TAttributeType>(type, predicate) != null;
        }

        // Members and properties
        public static List<Attribute> GetMemberAttributes<TType>(Expression<Func<TType, object>> action)
        {
            return GetMemberAttributes(GetMember(action));
        }

        public static List<TAttributeType> GetMemberAttributes<TType, TAttributeType>(
            Expression<Func<TType, object>> action,
            Func<TAttributeType, bool> predicate = null)
            where TAttributeType : Attribute
        {
            return GetMemberAttributes<TAttributeType>(GetMember(action), predicate);
        }

        public static TAttributeType GetMemberAttribute<TType, TAttributeType>(
            Expression<Func<TType, object>> action,
            Func<TAttributeType, bool> predicate = null)
            where TAttributeType : Attribute
        {
            return GetMemberAttribute<TAttributeType>(GetMember(action), predicate);
        }

        public static bool HasMemberAttribute<TType, TAttributeType>(Expression<Func<TType, object>> action, Func<TAttributeType, bool> predicate = null) where TAttributeType : Attribute
        {
            return GetMemberAttribute(GetMember(action), predicate) != null;
        }

        // MemberInfo (and PropertyInfo since PropertyInfo inherits from MemberInfo)
        public static List<Attribute> GetMemberAttributes(this MemberInfo memberInfo)
        {
            return
                LockAndGetAttributes(memberInfo, mi => ((MemberInfo)mi).GetCustomAttributes(true));
        }

        public static List<TAttributeType> GetMemberAttributes<TAttributeType>(this MemberInfo memberInfo, Func<TAttributeType, bool> predicate = null) where TAttributeType : Attribute
        {
            return
                GetMemberAttributes(memberInfo)
                    .Where<Attribute, TAttributeType>()
                    .Where(attr => predicate == null || predicate(attr))
                    .ToList();
        }

        public static TAttributeType GetMemberAttribute<TAttributeType>(this MemberInfo memberInfo, Func<TAttributeType, bool> predicate = null) where TAttributeType : Attribute
        {
            return
                GetMemberAttributes<TAttributeType>(memberInfo, predicate)
                    .FirstOrDefault();
        }

        public static bool HasMemberAttribute<TAttributeType>(this MemberInfo memberInfo, Func<TAttributeType, bool> predicate = null) where TAttributeType : Attribute
        {
            return
                memberInfo.GetMemberAttribute<TAttributeType>(predicate) != null;
        }

        // Internal stuff
        private static IEnumerable<TType> Where<X, TType>(this IEnumerable<X> list)
        {
            return
                list
                    .Where(item => item is TType)
                    .Cast<TType>();
        }

        private static TType FirstOrDefault<X, TType>(this IEnumerable<X> list)
        {
            return
                list
                    .Where<X, TType>()
                    .FirstOrDefault();
        }

        private static List<Attribute> LockAndGetAttributes(object key, Func<object, object[]> retrieveValue)
        {
            return
                LockAndGet<object, List<Attribute>>(_attributeCache, key, mi => retrieveValue(mi).Cast<Attribute>().ToList());
        }

        // Method for thread safely executing slow method and storing the result in a dictionary
        private static TValue LockAndGet<TKey, TValue>(Dictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TValue> retrieveValue)
        {
            TValue value = default(TValue);
            lock (dictionary)
            {
                if (dictionary.TryGetValue(key, out value))
                {
                    return value;
                }
            }

            value = retrieveValue(key);

            lock (dictionary)
            {
                if (dictionary.ContainsKey(key) == false)
                {
                    dictionary.Add(key, value);
                }

                return value;
            }
        }

        private static MemberInfo GetMember<T>(Expression<Func<T, object>> expression)
        {
            MemberExpression memberExpression = expression.Body as MemberExpression;

            if (memberExpression != null)
            {
                return memberExpression.Member;
            }

            UnaryExpression unaryExpression = expression.Body as UnaryExpression;

            if (unaryExpression != null)
            {
                memberExpression = unaryExpression.Operand as MemberExpression;

                if (memberExpression != null)
                {
                    return memberExpression.Member;
                }

                MethodCallExpression methodCall = unaryExpression.Operand as MethodCallExpression;
                if (methodCall != null)
                {
                    return methodCall.Method;
                }
            }

            return null;
        }
    }
}

And here’s a number of nunit tests;

[TestFixture]
class AttributeHelperTests
{
[MyAttribute(Name = "Steve")]
internal class Attributed
{
[MyAttribute(Name = "Bob")]
public bool HasAttributeProperty { get; set; }
public bool HasNoAttributeProperty { get; set; }

[MyAttribute(Name = "Stevie")]
public bool HasAttributeMember(int x)
{
return true;
}

public bool HasNoAttributeMember(int x)
{
return true;
}
}

internal class MyAttribute : Attribute
{
public string Name { get; set; }
}

[Test]
public void GetTypeAttributes_works()
{
Assert.That(AttributeHelper.GetTypeAttributes<Attributed>().Count, Is.EqualTo(1));
Assert.That(AttributeHelper.GetTypeAttributes<Attributed, MyAttribute>().Count, Is.EqualTo(1));
Assert.That(AttributeHelper.GetTypeAttributes<Attributed, MyAttribute>(attr => attr.Name == "Jane").Count, Is.EqualTo(0));
Assert.That(AttributeHelper.GetTypeAttributes<Attributed, MyAttribute>(attr => attr.Name == "Steve").Count, Is.EqualTo(1));
}

[Test]
public void GetTypeAttribute_works()
{
Assert.That(AttributeHelper.GetTypeAttribute<Attributed, MyAttribute>(), Is.Not.Null);
Assert.That(AttributeHelper.GetTypeAttribute<Attributed, SequentialAttribute>(), Is.Null);

Assert.That(AttributeHelper.GetTypeAttribute<Attributed, MyAttribute>(attr => attr.Name == "Jane"), Is.Null);
Assert.That(AttributeHelper.GetTypeAttribute<Attributed, MyAttribute>(attr => attr.Name == "Steve"), Is.Not.Null);
}

[Test]
public void HasTypeAttribute_works()
{
Assert.That(AttributeHelper.HasTypeAttribute<Attributed, MyAttribute>(), Is.True);
Assert.That(AttributeHelper.HasTypeAttribute<Attributed, SequentialAttribute>(), Is.False);

Assert.That(AttributeHelper.HasTypeAttribute<Attributed, MyAttribute>(attr => attr.Name == "Jane"), Is.False);
Assert.That(AttributeHelper.HasTypeAttribute<Attributed, MyAttribute>(attr => attr.Name == "Steve"), Is.True);
}

[Test]
public void GetMemberAttributes_works()
{
Assert.That(AttributeHelper.GetMemberAttributes<Attributed>(x => x.HasAttributeMember(0)).Count, Is.EqualTo(1));
Assert.That(AttributeHelper.GetMemberAttributes<Attributed, MyAttribute>(x => x.HasAttributeMember(0)).Count, Is.EqualTo(1));
Assert.That(AttributeHelper.GetMemberAttributes<Attributed>(x => x.HasNoAttributeMember(0)).Count, Is.EqualTo(0));

Assert.That(AttributeHelper.GetMemberAttributes<Attributed>(x => x.HasAttributeProperty).Count, Is.EqualTo(1));
Assert.That(AttributeHelper.GetMemberAttributes<Attributed, MyAttribute>(x => x.HasAttributeProperty).Count, Is.EqualTo(1));
Assert.That(AttributeHelper.GetMemberAttributes<Attributed>(x => x.HasNoAttributeProperty).Count, Is.EqualTo(0));

Assert.That(AttributeHelper.GetMemberAttributes<Attributed, MyAttribute>(x => x.HasAttributeMember(0), attr => attr.Name == "Stevie").Count, Is.EqualTo(1));
Assert.That(AttributeHelper.GetMemberAttributes<Attributed, MyAttribute>(x => x.HasAttributeMember(0), attr => attr.Name == "X").Count, Is.EqualTo(0));

Assert.That(AttributeHelper.GetMemberAttributes<Attributed, MyAttribute>(x => x.HasAttributeProperty, attr => attr.Name == "Bob").Count, Is.EqualTo(1));
Assert.That(AttributeHelper.GetMemberAttributes<Attributed, MyAttribute>(x => x.HasAttributeProperty, attr => attr.Name == "X").Count, Is.EqualTo(0));
}

[Test]
public void GetMemberAttribute_works()
{
Assert.That(AttributeHelper.GetMemberAttribute<Attributed, MyAttribute>(x => x.HasAttributeMember(0)), Is.Not.Null);
Assert.That(AttributeHelper.GetMemberAttribute<Attributed, MyAttribute>(x => x.HasNoAttributeMember(0)), Is.Null);

Assert.That(AttributeHelper.GetMemberAttribute<Attributed, MyAttribute>(x => x.HasAttributeMember(0), attr => attr.Name == "Stevie"), Is.Not.Null);
Assert.That(AttributeHelper.GetMemberAttribute<Attributed, MyAttribute>(x => x.HasAttributeMember(0), attr => attr.Name == "X"), Is.Null);
}

[Test]
public void HasMemberAttribute_works()
{
Assert.That(AttributeHelper.HasMemberAttribute<Attributed, MyAttribute>(x => x.HasAttributeMember(0)), Is.True);
Assert.That(AttributeHelper.HasMemberAttribute<Attributed, MyAttribute>(x => x.HasNoAttributeMember(0)), Is.False);

Assert.That(AttributeHelper.HasMemberAttribute<Attributed, MyAttribute>(x => x.HasAttributeMember(0), attr => attr.Name == "Stevie"), Is.True);
Assert.That(AttributeHelper.HasMemberAttribute<Attributed, MyAttribute>(x => x.HasAttributeMember(0), attr => attr.Name == "X"), Is.False);
}
}

Download Stock Quotes, Free, Easy and with Source Code

Every once in a while, I need stock quotes for some idea I need to try out. There are several methods for downloading quotes that cost money – but the data is freely available from  Yahoo so I figured I’d use that.

Turns out that 93 rows of code is enough – and that includes downloading a list of Nasdaq stock symbols.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Cluster.ConsoleApp
{
    public static class MinimalStockDownloader
    {
        public static void DownloadStocks(string path)
        {
            // Allows you to download more items in parallel
            ServicePointManager.DefaultConnectionLimit = 10;
            List<string> symbols = GetStockSymbols();

            // Run in parallel - speeds things up considerably...
            Parallel.ForEach(
                symbols,
                symbol =>
                {
                    Console.WriteLine("Downloading {0}: Working...", symbol);
                    string suri = string.Format(
                        "http://ichart.finance.yahoo.com/table.csv?s={0}&g=d&ignore=.csv", 
                        symbol);                    
                    try
                    {
                        string quotes = Get(new Uri(suri));
                        File.WriteAllText(path + @"\" + symbol + ".csv", quotes);                    
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(
                            "  Failed to download {0} with exception: \n{1}", 
                            symbol, 
                            e);
                    }
                    
                    Console.WriteLine(
                        "Downloading {0}: Done!", 
                        symbol);
                });
        }

        public static List<string> GetStockSymbols()
        {
            // You'll find a complete list of stocks at
            // http://www.nasdaq.com/screening/companies-by-industry.aspx?exchange=NASDAQ&render=download
            // referrred to by http://www.nasdaq.com/screening/companies-by-industry.aspx?exchange=NASDAQ
            string stocksCsv = Get(new Uri("http://www.nasdaq.com/screening/companies-by-industry.aspx?exchange=NASDAQ&render=download"));

            List<string> symbols = new List<string>();
            Regex regexObj = new Regex("^\"(.*?)\"", RegexOptions.Singleline | RegexOptions.Multiline);
            Match matchResult = regexObj.Match(stocksCsv);
            while (matchResult.Success)
            {
                symbols.Add(matchResult.Groups[1].Value);
                matchResult = matchResult.NextMatch();
            }

            // First item is the text "Symbol".
            symbols = symbols.Skip(1).ToList();
            Console.WriteLine("Found {0} symbols", symbols.Count);
            return symbols;
        }

        public static string Get(Uri address)
        {
            Console.WriteLine("  Get {0}...", address);
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
            request.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.CacheIfAvailable);

            try
            {
                using (WebResponse response = request.GetResponse())
                using (var stream = response.GetResponseStream())
                using (var reader = new StreamReader(stream, Encoding.Default))
                {
                    return reader.ReadToEnd();
                }
            }
            catch
            {
                request.Abort();
                throw;
            }
        }
    }
}

Colored/Shaded Rectangle on a WriteableBitmap

I recently needed a way to render a colored rectangle on a WriteableBitmap in Silverlight – though the code could be used in WPF with minor changes. Typically, you’d not use WriteableBitmaps but different Shapes in WPF, but this time I needed to create my own bitmap.

I’ve submitted the code as a contribution to the WriteableBitmapEx.codeplex.com project, but it hasn’t been accepted nor rejected yet, so I figured I’d post it here in case anyone ever needs something similar.

Drawing a 255×255 shaded block takes 2.06 ms (averaged over 1000 draws).

Shaded rectangle rendered on picture of lena;

WriteableBitmap bitmap = new WriteableBitmap((BitmapSource)Image.Source);
int width = 255;
int start = (512 - width) / 2;
bitmap.DrawFilledRectangle(
 start, start,
 start + width, start + width,
 Colors.White,
 Colors.Red,
 Colors.Green,
 Colors.Blue);

Image.Source = bitmap;
bitmap.Invalidate();

public static void DrawFilledRectangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, Color color)
{
	// Add one to use mul and cheap bit shift for multiplicaltion
	var a = color.A + 1;
	var col = (color.A << 24)
			 | ((byte)((color.R * a) >> 8 ) << 16)
			 | ((byte)((color.G * a) >> 8 ) << 8 )
			 | ((byte)((color.B * a) >> 8 ));

	bmp.DrawFilledRectangle(x1, y1, x2, y2, col);
}

public static void DrawFilledRectangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, Color color00, Color color01, Color color10, Color color11)
{
	// Add one to use mul and cheap bit shift for multiplicaltion
	var a00 = color00.A + 1;
	var col00 = (color00.A << 24)
			 | ((byte)((color00.R * a00) >> 8 ) << 16)
			 | ((byte)((color00.G * a00) >> 8 ) << 8 )
			 | ((byte)((color00.B * a00) >> 8 ));

	var a01 = color01.A + 1;
	var col01 = (color01.A << 24)
			 | ((byte)((color01.R * a01) >> 8 ) << 16)
			 | ((byte)((color01.G * a01) >> 8 ) << 8 )
			 | ((byte)((color01.B * a01) >> 8 ));

	var a10 = color10.A + 1;
	var col10 = (color10.A << 24)
			 | ((byte)((color10.R * a10) >> 8 ) << 16)
			 | ((byte)((color10.G * a10) >> 8 ) << 8 )
			 | ((byte)((color10.B * a10) >> 8 ));

	var a11 = color11.A + 1;
	var col11 = (color11.A << 24)
			 | ((byte)((color11.R * a11) >> 8 ) << 16)
			 | ((byte)((color11.G * a11) >> 8 ) << 8 )
			 | ((byte)((color11.B * a11) >> 8 ));

	bmp.DrawFilledRectangle(x1, y1, x2, y2, col00, col01, col10, col11);
}

public static void DrawFilledRectangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int color)
{
	// Use refs for faster access (really important!) speeds up a lot!
	int w = bmp.PixelWidth;
	int h = bmp.PixelHeight;
	int[] pixels = bmp.Pixels;

	// Check boundaries
	if (x1 < 0) { x1 = 0; }
	if (y1 < 0) { y1 = 0; }
	if (x2 < 0) { x2 = 0; }
	if (y2 < 0) { y2 = 0; }
	if (x1 >= w) { x1 = w - 1; }
	if (y1 >= h) { y1 = h - 1; }
	if (x2 >= w) { x2 = w - 1; }
	if (y2 >= h) { y2 = h - 1; }

	int i = y1 * w;
	for (int y = y1; y < y2; y++)
	{
		int i2 = i + x1;
		while (i2 < i + x2)
		{
			pixels[i2++] = color;
		}
		i += w;
	}
}

public static void DrawFilledRectangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int color00, int color01, int color10, int color11)
{
	// Use refs for faster access (really important!) speeds up a lot!
	int w = bmp.PixelWidth;
	int h = bmp.PixelHeight;
	int[] pixels = bmp.Pixels;

	// Check boundaries
	if (x1 < 0) { x1 = 0; }
	if (y1 < 0) { y1 = 0; }
	if (x2 < 0) { x2 = 0; }
	if (y2 < 0) { y2 = 0; }
	if (x1 >= w) { x1 = w - 1; }
	if (y1 >= h) { y1 = h - 1; }
	if (x2 >= w) { x2 = w - 1; }
	if (y2 >= h) { y2 = h - 1; }

	// Retrieve the color channels
	byte a00 = (byte)(color00 >> 24); byte r00 = (byte)(color00 >> 16); byte g00 = (byte)(color00 >> 8 ); byte b00 = (byte)(color00);
	byte a10 = (byte)(color10 >> 24); byte r10 = (byte)(color10 >> 16); byte g10 = (byte)(color10 >> 8 ); byte b10 = (byte)(color10);
	byte a01 = (byte)(color01 >> 24); byte r01 = (byte)(color01 >> 16); byte g01 = (byte)(color01 >> 8 ); byte b01 = (byte)(color01);
	byte a11 = (byte)(color11 >> 24); byte r11 = (byte)(color11 >> 16); byte g11 = (byte)(color11 >> 8 ); byte b11 = (byte)(color11);

	//r01, r10
	int xrange = x2 - x1;
	int yrange = y2 - y1;

	for (int x = 0; x < xrange; x++)
	{
		int negx = xrange - x;
		byte atop = (byte)((a00 * negx + a01 * x) / xrange);
		byte rtop = (byte)((r00 * negx + r01 * x) / xrange);
		byte gtop = (byte)((g00 * negx + g01 * x) / xrange);
		byte btop = (byte)((b00 * negx + b01 * x) / xrange);

		byte abottom = (byte)((a10 * negx + a11 * x) / xrange);
		byte rbottom = (byte)((r10 * negx + r11 * x) / xrange);
		byte gbottom = (byte)((g10 * negx + g11 * x) / xrange);
		byte bbottom = (byte)((b10 * negx + b11 * x) / xrange);

		for (int y = 0; y < yrange; y++)
		{
			int negy = yrange - y;
			int p = (y + y1) * w + x + x1;

			int color =
				(byte)((atop * negy + abottom * y) / yrange) << 24 |
				(byte)((rtop * negy + rbottom * y) / yrange) << 16 |
				(byte)((gtop * negy + gbottom * y) / yrange) << 8 |
				(byte)((btop * negy + bbottom * y) / yrange);

			pixels[p] = color;
		}
	}
}

Redust SEO Rules

I’m proud to announce a new site that focuses on Search Engine Optimization tools that I’m working on with a team of developers that’s called redust.com. Our first tool, SEO-Rules automatically validates a page against a large number of Search Engine Optimization Rules.

The redust.com application, which will host several different tools, we’re currently have very specific plans for two more tools.

Remove Google Stopwords From String

If you’re anything like me, you’ve often wondered “how do I remove google stopwords from my strings”? Well, maybe you haven’t, but this is the method I came up with to do just that.

Google stopwords are words that are ignored in your query and on indexing your web pages, things like “a”, “about”, “above”. Here’s a list of stopwords assumed to be used by search-engines; http://www.ranks.nl/resources/stopwords.html and here’s another; http://www.link-assistant.com/seo-stop-words.html.

My method converts this text;

This is a text with lots and lots of stopwords. It also talks
a bit about load balancing. Load balancing is not a stopword.

To this text;

      text   lots   lots   stopwords.
talks   bit   load balancing. Load balancing       stopword.

Note that there are many double spaces, which we’ll take care of next.

The actual regex for clearing out stopwords looks like this (I’m only using a few of the words here);

(?<=(\A|\s|\.|,|!|\?))(a|able|about|above|abroad)(?=(\s|\z|\.|,|!|\?))

Btw, I use the awesome Regex Buddy for all my Regex needs- Regex Buddy, you’re my buddy too!

The Regex uses look-ahead and look-behind which not all Regex engines supports, and Regex formats may be differ. The reason it uses look-ahead and look-behind is that we don’t want the regex to “eat” the word separators, because if it did it would lose every second word that matches the regex. Believe me, it’s true, or use – you guessed it – Regex buddy to confirm.

If you’re clever, like me, you’ll be able to read the regex like it was plain english… ok, it’s obtuse and obfuscated, but it works.

I generated it like this (after using aforementioned Regex Buddy to determine the format);

string[] stopwords = File.ReadAllLines("EnglishStopwords.txt");

string regexCode = 
  @"(?<=(\A|\s|\.|,|!|\?))(" + 
  string.Join("|", stopwords) + 
  @")(?=(\s|\z|\.|,|!|\?))";

Regex regex = new Regex(regexCode, RegexOptions.Singleline | RegexOptions.IgnoreCase);

string cleaned = regex.Replace(indata, " ");

As for removing the double spaces, use this;

Regex removeDoubleWhiteSpace = 
  new Regex(@"\s{2,}", RegexOptions.Singleline | RegexOptions.IgnoreCase);

string cleaned = 
  removeDoubleWhiteSpace.Replace(cleaned, " ");

So, this is a rather compact version of what I’m doing;

public static void Test()
{
    string text =
        @"This is a text with lots and lots of stopwords. It also" + Environment.NewLine +
            "talks a bit about load balancing. Load balancing is not a stopword.";

    Console.WriteLine("Before:");
    Console.WriteLine(text);

    string[] stopwords = File.ReadAllLines(@"c:\slask\EnglishStopwords.txt");

    string regexCode = 
        @"(?<=(\A|\s|\.|,|!|\?))(" + 
        string.Join("|", stopwords) + 
        @")(?=(\s|\z|\.|,|!|\?))";

    Regex regex = new Regex(regexCode, RegexOptions.Singleline | RegexOptions.IgnoreCase);
            
    string cleaned = regex.Replace(text, " ");

    Console.WriteLine("\nAfter remove stopwords:");
    Console.WriteLine(text);

    Regex removeDoubleWhiteSpace = 
        new Regex(@"\s{2,}", RegexOptions.Singleline | RegexOptions.IgnoreCase);

    cleaned = 
        removeDoubleWhiteSpace.Replace(cleaned, " ");

    Console.WriteLine("\nAfter remove double white spaces:");
    Console.WriteLine(cleaned);
}

and the output looks like this;

Before:

This is a text with lots and lots of stopwords. It also

talks a bit about load balancing. Load balancing is not a stopword.

After remove stopwords:

This is a text with lots and lots of stopwords. It also

talks a bit about load balancing. Load balancing is not a stopword.

After remove double white spaces:

text lots lots stopwords. talks bit load balancing. Load balancing stopword.

PicoGA: Evolving a 3D Projection Matrix

In my previous blog post PicoGA  – a tiny GA for C# I talk about PicoGA and I demonstrate a few problems that can be solved using it. One of the examples is evolving a 3D Projection Matrix from a few pixel to world coordinate mappings taken from a given photograph.

The example didn’t use “height” in the picture because it contained no heights that I could be sure of. In this example, I’m using the heights of the goal posts in the picture below to show that it  can correctly handle World (x,y,z) to Screen(x,y) mapping.

From this picture I’ve identified 9 points that I’ve determined the World(x,y,z) coordinates (the football field is 105×68 meters, the goal is 2.44 meters high and 7.32 meters wide). The coordinates are specified below the picture.

new-pitch-with numbers

I simply use MS Paint (yay!) to determine the pixel coordinate, and I use the given dimensions of the football field (105×68) to determine the world coordinates;

    new WorldToScreenCase(688, 349, 0,0 ,0), // 1
    new WorldToScreenCase(454, 155, 52.5,0,0), // 2
    new WorldToScreenCase(353, 70,  105,0,0), // 3
    new WorldToScreenCase(127, 169, 52.5, 34,0), // 4
    new WorldToScreenCase(155, 411, 0, 34,0), // 5
    new WorldToScreenCase(220, 364, 0, 34 - 7.32*0.5, 2.44), // 6
    new WorldToScreenCase(80,  378, 0, 34+7.32*0.5,2.44), // 7
    new WorldToScreenCase(92,  57,  105, 34 + 7.32*0.5, 2.44), // 8
    new WorldToScreenCase(145, 56,  105, 34-7.32*0.5,2.44), // 9

It takes a while, here’s a video of evolution in action;

but the program is successful in evolving an appropriate matrix;

image

As you can see, the evolved matrix (the red dots) hits the measured points (blue dots) with quite high accuracy. This matrix can now be used for animating something moving across the football field!

As I stated in my previous post, there are analytical methods for doing this, but I’ve been unable to locate any, and this is a cool use for GA…

This is the code that I use to map from world coordinates to screen coordinates, using my evolved matrix;

private static Point3D ProjectCase(Point3D point, List&lt;double&gt; l)
{
	Point3D p = new Point3D(
		point.X - l[12] * 100,
		point.Y - l[13] * 100,
		point.Z - l[14] * 100);

	Point3D result = new Point3D(
		l[0] * p.X + l[1] * p.Y + l[2] * p.Z + l[3],
		l[4] * p.X + l[5] * p.Y + l[6] * p.Z + l[7],
		l[8] * p.X + l[9] * p.Y + l[10] * p.Z + l[11]);

	if (result.Z != 0)
	{
		result.X *= l[15] / result.Z;
		result.Y *= l[15] / result.Z;
	}

	return result;
}

 

You can find the source code among the PicoGA demos.

PicoGA – a tiny GA for C#

Have you ever found that you really want an extremely tiny and simple Genetic Algorithm method for optimizing a set of doubles (the genotype) given a fitness function? Me too!!! So, I wrote one, because it seemed fun.

I’m using it to evolve two toy problems, later I hope to show it with a slightly less toyish problem.

It’s really small (224 lines of code in a single file). It would be very easy to make it smaller – but then it’d be less readable. It would be equally simple to add new functionality, but then it would be larger and would no longer qualify for the name PicoGA. You can find PicoGA here http://picoga.codeplex.com/

What can you use a GA for?

First, two toy problems;

Find three doubles that sum up to five!

Not very difficult, but as I said, it’s a toy problem. First we must specify;

  • a fitness function
  • a population size (how many individuals (I just picked 20 for this simple problem))
  • a genome size / number of genes (3).

That comes out as one line of code;

      GA ga = new GA(
        20, // Individuals
        3, // Genotype length (number of doubles)
        individual => // Fitness function
          Math.Abs(5 - individual.Genotype.Sum(val => val)) 
        );

Simple! Now we need to run that for a couple of generations – but PicoGA takes care of that also. For each generation, we publish the results, if they’ve improved since the previous generation;

private static void SumTo5()
{
  Console.WriteLine("Sum to 5:...");
  GA ga = new GA(
    20, // Individuals
    3, // Genotype length (number of doubles)
    individual => // Fitness function
      Math.Abs(5 - individual.Genotype.Sum(val => val))
    );

  ga.RunEpoch(
    500, // Number of generations to run for
    null, // Action to perform for each generation
    () => // Action to perform once fitness has improved
    {
      Console.WriteLine(
        "Gen {2}: Fit={1}, Genotype={0}",
        string.Join(
          " ",
          ga.BestIndividual.Genotype.Select(val => val.ToString("0.00"))),
        ga.BestIndividual.Fitness.ToString("0.00"),
        ga.CurrentEpochGeneration);
    });

  Console.WriteLine("Sum to 5: done!");
  Console.WriteLine("");
}

 

Voilá, that’s all there is to it! For my test run, at generation 45 a solution is found;

PicoGA, demos

Sum to 5:...

Gen 0: Fit=3,39, Genotype=0,84 0,50 0,26

Gen 1: Fit=3,26, Genotype=0,97 0,50 0,26

Gen 43: Fit=0,04, Genotype=2,45 1,38 1,13

Gen 44: Fit=0,01, Genotype=2,48 1,38 1,13

Gen 45: Fit=0,00, Genotype=2,49 1,38 1,13

Sum to 5: done!

Find 1 2 3 4 5

For my second toy problem, I want the GA to find the values 1 2 3 4 5 (in that exact order) for it’s five genes. Again, not a very useful thing to do, possibly even less useful than my first example, but it’s a toy problem;

private static void Find12345()
{
    Console.WriteLine("Find 1 2 3 4 5:...");
    GA ga = new GA(
        200, // Number of individuals
        5, // Number of genes in the genotype
        individual => // Fitness function
        Math.Abs(individual.Genotype[0] - 1) +
        Math.Abs(individual.Genotype[1] - 2) +
        Math.Abs(individual.Genotype[2] - 3) +
        Math.Abs(individual.Genotype[3] - 4) +
        Math.Abs(individual.Genotype[4] - 5));

    ga.RunEpoch(500, null, () =>
        {
            Console.WriteLine(
                "Gen {2}: Fit={1}, Genotype={0}",
                string.Join(
                " ", 
                ga.BestIndividual.Genotype.Select(
                    val => val.ToString("0.00"))),
                ga.BestIndividual.Fitness.ToString("0.00"),
                ga.CurrentEpochGeneration);
        });

    Console.WriteLine("Find 1 2 3 4 5: done!");
    Console.WriteLine("");
}

 

At generation 105 a perfect solution is found. The reason it takes so long is that genes only mutated slowly and reaching 5 took a while. I’ve since upped mutation rate.

Gen 105: Fit=0,00, Genotype=1,00 2,00 3,00 4,00 5,00

Ok, but what can I really use it for? No more toy problems!

Well, lots and lots of stuff!

I once had an image of a soccer field and I needed a 3D perspective projection matrix that matched the image. I needed to render football players as they were moving around the pitch, for which I had pitch coordinates. But I needed to convert those pitch coordinates to screen coordinates, which isn’t as simple as it sounds.

The 3d Perspective Projection Matrix contains all information about the setup of the camera and target as the image was shot. Camera Field Of View, position of camera relative to subject, orientation of camera with regard to subject etc. For this I used a genotype of 18 genes (in effect 18 doubles).

The data we need

The pitch looked something like this;

image

First I measure points on the I could pinpoint pixels in the image and determine where they where in soccer field space and tie that to image space coordinates.

image

I compiled a list like this (a soccer pitch is 105 x 68 meters)

  1. Pixel 165,178=> World 0, 0, 0
  2. Pixel 377,120=> World 52.5, 0, 0
  3. Pixel 513, 85=> World 105, 0, 0
  4. Pixel 473, 157=>World 52.5, 34, 0
  5. Pixel 611, 208 =>World 52.5, 68, 0
  6. Pixel 735, 136 => World 105, 68, 0

There are analytical methods of retrieving the matrix given only that information, but I don’t know them and I couldn’t find them by googling. But I know GA, and using GA I evolved the matrix!

The fitness function

The fitness function is basically that we feed the six world coordinates into the 3d transformation matrix and sum up the errors of the pixel coordinates it suggests as compared to the pixel coordinates we previously measured. Trivial. Not really, because the formula for transforming from 3D space to 2D screen space isn’t trivial. This is the code I wound up using for this;

private static Point3D ProjectCase(Point3D point, List<double> l)
{
    Point3D p = new Point3D(
        point.X - l[12] * 100,
        point.Y - l[13] * 100,
        point.Z - l[14] * 100);

    Point3D result = new Point3D(
        l[0] * p.X + l[1] * p.Y + l[2] * p.Z + l[3],
        l[4] * p.X + l[5] * p.Y + l[6] * p.Z + l[7],
        l[8] * p.X + l[9] * p.Y + l[10] * p.Z + l[11]);

    if (result.Z != 0)
    {
        result.X *= l[15] / result.Z;
        result.Y *= l[15] / result.Z;
    }

    result.X += l[16] * 100;
    result.Y += l[17] * 100;

    return result;
}

 

Some of the times, PicoGA quickly (in a matter of minutes) finds a matrix that it likes. I’ve plotted in the pixels that the generated matrix produces in the picture below. They’re not perfect, but neither are the measurements that were used for generating the matrix, so they can never be perfect. The red dots are where the evolved matrix suggested;

image

Here’s the program for evolving the matrix;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Media3D;

namespace PicoGA
{
    public static class FindMatrix
    {
        internal class WorldToScreenCase
        {
            public WorldToScreenCase(double screenX, double screenY, double worldX, double worldY)
            {
                Screen = new Point3D(screenX, screenY, 0);
                World = new Point3D(worldX, worldY, 0);
            }

            internal Point3D Screen { get; set; }
            internal Point3D World { get; set; }
        }

        public static void FindProjectionMatrix()
        {
            Console.WriteLine("Find ProjectionMatrix:...");
            List<WorldToScreenCase> cases =
                new List<WorldToScreenCase>
                {						
                    // Old Image
                    new WorldToScreenCase(165,178 ,       0,      0),
                    new WorldToScreenCase(377,120 ,       52.5,      0),
                    new WorldToScreenCase(513,85 ,       105,      0),
                    new WorldToScreenCase(473,157 ,       52.5,      34),
                    new WorldToScreenCase(611,208 ,       52.5,      68),
                    new WorldToScreenCase(735,136 ,       105,      68),
                };

            GA ga = new GA(
                2000, // Number of individuals
                18, // Number of genes in the genotype
                individual => // Fitness function
                {
                    double errorSum = 0;
                    foreach (WorldToScreenCase test in cases)
                    {
                        Point3D testScreen = ProjectCase(test.World, individual.Genotype);
                        double sqrError = (testScreen - test.Screen).LengthSquared;
                        errorSum += sqrError;
                    }

                    return errorSum;
                });

            ga.RunEpoch(10000,
                () =>
                {
                    ga.BreakEpochRun = ga.BestIndividual.Fitness <= 1.0 || Console.KeyAvailable;
                },
                () =>
                {
                    Console.WriteLine(
                        "Gen {2}: Fit={1}, Genotype={0}",
                        string.Join(
                        " ",
                        ga.BestIndividual.Genotype.Take(5).Select(
                            val => val.ToString("0.00"))),
                        ga.BestIndividual.Fitness.ToString("0.00"),
                        ga.CurrentEpochGeneration);
                });

            if (Console.KeyAvailable)
            {
                Console.ReadKey();
            }

            Console.WriteLine("Results for training set:");
            foreach (WorldToScreenCase test in cases)
            {
                ShowTestResult(ga, test);
            }

            Console.WriteLine("");
            Console.WriteLine("Additional tests:");
            ShowTestResult(ga, new WorldToScreenCase(120, 73, 105, 34));

            Console.WriteLine("Find ProjectionMatrix: done!");
            Console.WriteLine("");
        }

        private static void ShowTestResult(GA ga, WorldToScreenCase test)
        {
            Point3D p = ProjectCase(test.World, ga.BestIndividual.Genotype);
            Console.WriteLine(
                " World ({0:0.00}, {1:0.00}) => \n" +
                "   Wanted:({2:0.00}, {3:0.00}) \n" +
                "   Received:({4:0.00}, {5:0.00})",
                test.World.X,
                test.World.Y,
                test.Screen.X,
                test.Screen.Y,
                p.X,
                p.Y);
        }

        private static Point3D ProjectCase(Point3D point, List<double> l)
        {
            Point3D p = new Point3D(
                point.X - l[12] * 100,
                point.Y - l[13] * 100,
                point.Z - l[14] * 100);

            Point3D result = new Point3D(
                l[0] * p.X + l[1] * p.Y + l[2] * p.Z + l[3],
                l[4] * p.X + l[5] * p.Y + l[6] * p.Z + l[7],
                l[8] * p.X + l[9] * p.Y + l[10] * p.Z + l[11]);

            if (result.Z != 0)
            {
                result.X *= l[15] / result.Z;
                result.Y *= l[15] / result.Z;
            }

            result.X += l[16] * 100;
            result.Y += l[17] * 100;

            return result;
        }
    }
}

 

You can find PicoGA here http://picoga.codeplex.com/.

SQL Server Profiler and LINQ to SQL

If you’re using LINQ to SQL, you’re eventually likely to be required to trace SQL statements from the SQL Server Profiler. Either for performance purposes or for debugging purposes. When you do, you’ll find that you’re in a world of hurt!

Below, I’ll demonstrate what I’m using and which may not be perfect, but it’s a huge step in the right direction!

A world of hurt

So, you want to trace a SQL statement back to the LINQ code that generated it? You’re really in it now! The reason is that when you execute LINQ to SQL statements, they can generate any number of SQL statements and it’s near impossible to trace them back to the individual statements that generated them. Especially on a busy production server where lots and lots of stuff is happening in the profiler

Even worse, you’ll typically have DAL (Data Access Layer) methods that are similar to how you’d use stored procedures previously, that execute a number of LINQ to SQL statements. So the offending SQL might be a tiny part of a large set of SQL statements originating from a particular DAL method.

What I’d like

I’d love to have a method for tracing every single LINQ to SQL statement from SQL Server Profiler back to my code in Visual Studio. But I haven’t been able to find a method for doing this.

What I’ve got out of the box

Basically, I have a long long long list of SQL statements in a log that I have no chance of matching up with the actual code.

What I’ve come up with

I’ve been able to add a line in the SQL Server Profiler logs as each DAL method starts and when it ends – that way I’m able to determine which DAL method a particular SQL Statements belongs to.

The naive way

Now, this can be done relatively straight forward, we’ll simply add a comment at the start and at the end of the DAL method – but this makes our code messy and hard to read. Especially if we get fancy and do a try/catch to make our code safer.

This is what the code looks to start out with (we’re using a data context factory);

        private static List<Employee> GetEmployees()
        {
            using (MyDataClassesDataContext context = 
new MyDataClassesDataContext())
            {
                return
                    context
                        .Employees
                        .Where(employee => employee.LastName.StartsWith("a"))
                        .ToList();
            }
        }

 

Adding some logging;

        private static List<Employee> GetEmployees()
        {
            using (MyDataClassesDataContext context = 
new MyDataClassesDataContext())
            {
                context.ExecuteCommand("BeginCall: GetEmployees");
                List<Employee> employees =
                    context
                        .Employees
                        .Where(employee => employee.LastName.StartsWith("a"))
                        .ToList();
                context.ExecuteCommand("EndCall: GetEmployees");
                return employees;
            }
        }

 

That

  • looks pretty bad
  • we had to refactor the code to use a temporary variable – which is ok if you need it but fairly pointless in this case
  • we must add the logging code to every DAL method!
  • the risks of missing one or a few are fairly large
  • we want to be safe against refactoring (the method changes name)
  • if the call fails with an exception, the exception will prevent the “EndCall” text from ever making it to the log.

What to do?

A cleverer way

Instead we add BeginCall every time the context is created and EndCall every time dispose is called, which allows us to structure our methods the same way as before and forces us to add the logging code. Also, instead of sending the actual name of the method, we use reflection and send MethodInfo – that makes it refactoring safe.

This is what the method call looks like – note that the logging part is invisible, the only change from the original method is the call to GetCurrentMethod

        private static List<Employee> GetEmployees()
        {
            using (MyDataClassesDataContext context =
new MyDataClassesDataContext(MethodBase.GetCurrentMethod()))
            {
                return
                    context
                        .Employees
                        .Where(employee => employee.LastName.StartsWith("a"))
                        .ToList();
            }
        }

 

Next we need to log stuff, MyDataClassesDataContext is a class that’s autogenerated by the DBML editor (as used with LINQ to SQL), but it’s partial so adding stuff is fairly straight forward.

The tricky part is that DataContext, which MyDataClassesDataContext  inherits from, implements Dispose and if we try to override the Dispose method of MyDataClassesDataContext, we’ll not be able to log anything, because that method is called once the context is allready disposed!

But not to worry, we simply re-implement Dispose and call the base method once we’ve logged what we need;

using System;
using System.Reflection;

namespace TraceLINQToSQL
{
    partial class MyDataClassesDataContext : IDisposable
    {
        private readonly string _methodName;

        public MyDataClassesDataContext(MethodBase methodBase)
            : this()
        {
            _methodName = methodBase.DeclaringType.FullName + "." + methodBase.Name;
            AddLogEntry("BeginCall Method={0}", _methodName);
        }

        public static bool LoggingEnabled { get; set; }

        public new void Dispose()
        {
            AddLogEntry("EndCall Method={0}", _methodName);
            base.Dispose();
        }

        private void AddLogEntry(string paramString, params object[] args)
        {
            if (LoggingEnabled)
            {
                ExecuteCommand("--" + string.Format(paramString, args));
            }
        }
    }
}

 

With this, every DAL method should start logging every call so that traceability is greatly improved. However, the cost is two extra roundtrips to the database per DAL method, so it might be a good idea to turn off logging for production. But in my tests, the overhead was negligible.

Going forward

From this, things could be greatly improved with a tool; a tool that groups all SQL statements from a single DAL call and sum up roundtrips/reads/writes/duration/CPU usage etc.

A method that counts how many times each DAL method is called. I haven’t had the time to create such a tool, but if you know of one, please let us know!

Follow

Get every new post delivered to your Inbox.