Setting your database Compatibility Level to match the SQL Server version

by Alex Meyer-Gleaves 7 March 2010 - 11:49 PM

It is not uncommon to have databases with a Compatibility Level that does not match the version of SQL Server they are running on. When you upgrade a SQL Server installation the databases retain a Compatibility Level that matches the version you upgraded from. The same applies to restoring or attaching databases from an earlier version.

I wrote the script below to set the Compatibility Level of a database to match the version of SQL Server. It is designed to work only on SQL Server 2005 and SQL Server 2008 instances. It uses the sys.databases view that does not exist in SQL Server 2000. I decided to use this view because I knew the script would not be executed on a SQL Server 2000 instance.

DECLARE @database nvarchar(128)
SET @database = 'Foo'

DECLARE @databaseLevel tinyint
SELECT @databaseLevel = compatibility_level FROM sys.databases WHERE name = @database
IF @databaseLevel IS NULL
    BEGIN
        PRINT N'The database ''' + @database + ''' does not exist.'
        RETURN
    END

PRINT N'Database Compatibility Level: ' + CONVERT(nvarchar, @databaseLevel)

DECLARE @productVersion nvarchar(128)
SELECT @productVersion = CONVERT(nvarchar(128), SERVERPROPERTY('ProductVersion'))
PRINT N'Server Product Version: ' + @productVersion

DECLARE @majorVersion tinyint
SELECT @majorVersion = CONVERT(tinyint, SUBSTRING(@productVersion, 0, CHARINDEX('.' , @productVersion)))
PRINT N'Server Major Version: ' + CONVERT(nvarchar, @majorVersion)

DECLARE @serverLevel tinyint
SET @serverLevel = @majorVersion * 10
PRINT N'Server Compatibility Level: ' + CONVERT(nvarchar, @serverLevel)

IF @databaseLevel = @serverLevel
    BEGIN
        PRINT N'The Compatibility Level for ''' + @database + ''' already matches the SQL Server version.'     
        RETURN
    END

DECLARE @query nvarchar(max)
SET @query = N'ALTER DATABASE [' + @database + '] SET SINGLE_USER'
EXEC sp_executesql @query

EXEC sp_dbcmptlevel @database, @serverLevel
PRINT N'The Compatibility Level for ''' + @database + ''' has been updated.'

SET @query = N'ALTER DATABASE [' + @database + '] SET MULTI_USER'
EXEC sp_executesql @query

Tags:

Categories: Database

Comment Spam protection for BlogEngine.NET

by Alex Meyer-Gleaves 25 February 2010 - 12:38 AM

image The amount of comment spam I have been getting on this blog has increased significantly in recent months, and I decided it was finally time to do something about it. I have been using an Akismet comment filtering extension for a long time now but the flow of comment spam continued to rise. There is now an Akismet extension included in BlogEngine.NET 1.6 and I will continue to use it because the more layers of protection the better.

I wanted to complement the Akismet extension with a CAPTCHA based solution and figured that the problem would no doubt have already been tackled by someone else. This was certainly the case, and after settling on this solution outlined by Michael Ceranski, I had the implementation deployed and working in a couple of minutes. The only hesitation I had with the solution is that it requires changes to the BlogEngine.NET code, and I will have to remember to merge them into newer versions when I upgrade. I usually have a number of changes to merge during an upgrade anyway, and if the end result is less spam then it will be well worth it. Now to wait and see how well this CAPTCHA based solution works.

Tags:

Categories: BlogEngine.NET

WSCF.blue now supports Visual Studio 2010 RC

by Alex Meyer-Gleaves 24 February 2010 - 12:56 AM

image There is another WSCF.blue update (V1.0.7) available for download on CodePlex. This update adds support for Visual Studio 2010 RC in addition to Visual Studio 2008. Please note that Visual Studio 2010 Beta 2 is not supported.

All features should work exactly the same way in both versions of Visual Studio. If you have any problems please jump onto the Issue Tracker and let us know.

I would also love to hear more about what features you would like to see in upcoming versions of WSCF.blue. If you have any thoughts please contact me or simply start a thread in the Discussions forum. Your feedback is always welcome.

Tags: ,

Categories: Web Services | WSCF

WSCF.blue V1.0.6 Update

by Alex Meyer-Gleaves 18 February 2010 - 1:20 AM

There is now a V1.0.6 update for WSCF.blue that includes fixes for a number of bugs that have been reported since the V1.0.5 release. It has taken some large and complex contracts to uncover some of the more obscure bugs. Below is a list of the bugs that have been fixed:

  • The data contract type filter was not including all the required types in some complex contracts.
  • When adjusting the casing of enumeration members references in DefaultValue attributes and constructors were not being updated.
  • When using the List<T> option along with the Public properties option the backing field used for properties was sometimes left as an array instead of a generic list.
  • When using the List<T> option along with the Public properties option the backing field used for properties with an XmlChoiceIdentifier attribute was converted to a generic list instead of being left as an array to match the property.
  • Fixed an Adjust casing bug related to enumeration values that cannot be used as valid property names. The XmlEnumAttribute was being set to the generic ItemX property name instead of being left with the value from the original enumeration.

If you have any problems with the update please let us know through the Issue Tracker. Thanks to everyone who has reported bugs.

Tags: ,

Categories: WSCF | Web Services

.NET Reflector V6 Released

by Alex Meyer-Gleaves 16 February 2010 - 1:14 PM

Reflector Logo With this latest release of the recently acquired Reflector tool, Red Gate have provided both free and paid versions. The free version only has a couple of new features, the first of which was already available in the TestDriven.NET add-in for Visual Studio:

  • Jump straight to .NET Reflector from Visual Studio
  • Support for .NET 4 assemblies

Red Gate have decided to bundle a trial of the paid version along with the free one. Even though they are still releasing a free version, I find the forced bundling of the trial a little annoying. They are certainly trying to sell this as a good thing on their website:

image

The paid version, marketed as .NET Reflector Pro, is actually a Visual Studio add-in and offers some additional features:

  • Integrates the power of .NET Reflector into Visual Studio
  • Decompile third-party assemblies from within VS
  • Step through decompiled assemblies and use all the debugging techniques you would use on your own code

These certainly are very cool features, but ones that I would like to be given the option of trailing. Regardless, at the end of the day Reflector is still free, and still rocks!

Tags:

Categories: Development Tools

More than 1000 downloads for WSCF.blue V1

by Alex Meyer-Gleaves 5 January 2010 - 12:41 AM

On the last day of September in 2009 we released the first version of WSCF.blue on CodePlex. I was very pleased to see that there has now been more than 1000 downloads of the V1 release. Congratulations to the team and thank you to everyone who has downloaded WSCF.blue. It is great to see that interest in contract-fist development is still alive and well. Of course, Christian and Buddhike did a great job of spreading the word with their excellent MSDN article.

image

Now that everyone is back from holidays and feeling refreshed there is no doubt work will continue on the next version. We all have plenty of ideas for the features we would like to see, but what we would really like is feedback from the community on what you want. If you have ideas on what you would like to see in future versions of WSCF.blue please jump onto the forum and let us know.

Tags:

Categories: WSCF | Web Services | Development Tools

Registering open generic types in Autofac 1.4

by Alex Meyer-Gleaves 3 January 2010 - 12:34 AM

UPDATE (5 January 2010): This feature has now been added to the Autofac 1.4 codebase. I had intended to get this one directly into the codebase but Nick and I got our wires crossed, and I ended up posting it as an extension instead. Regardless, this post remains a valid example of extending Autofac 1.4. The RegisterClosedTypesOf method will appear on the ContainerBuilder in the next 1.4 maintenance release. Until then you can use the extension below to register your open generic types.

This is a follow up to my recent post about writing an extension for registering open generic interface types in Autofac 2. The feature described in the first post, along with support for open generic classes, has since been added to the Autofac 2 codebase. You can grab the current 2.1 preview release on the download page and test it out.

I personally feel that the latest preview version of Autofac 2 is stable enough to start using, but I know that even when released not everyone will be able to adopt the new version as soon as they would like. For that reason I have decided to write a similar extension for Autofac 1.4 that supports both open generic interfaces and classes.

Before I move onto the code I would like to draw a distinction between this feature and the RegisterGeneric method found on instances of the the ContainerBuilder class in Autofac 1.4. The RegisterGeneric method allows you to register an open generic type and have a closed generic type created for you when requested. For example, registering List<> and then resolving List<string> will cause Autofac to create a new List<string> instance for you. The difference is that the RegisterGeneric feature does not locate existing types that close the open generic type being registered.

In the unit test below we are ensuring that a closing type is provided for an open generic interface. It is similar to that from the original post, except the extension method is called RegisterClosedTypesOf and extends ContainerBuilder instances instead of RegistrationBuilder instances. The extension method also has a parameter for the assembly that will be scanned to find the closing types. This is different from the Autofac 2 implementation were the assembly is provided to the RegisterAssemblyTypes method, and the containing types are filtered using a delegate provided to the RegistrationBuilder.

[Test]
public void RegisterClosedTypesOf_OpenGenericInterfaceTypeProvided_ClosingGenericTypesRegistered()
{
    ContainerBuilder builder = new ContainerBuilder();
    Assembly assembly = typeof(ICommand<>).Assembly;
    builder.RegisterClosedTypesOf(typeof(ICommand<>), assembly);
    IContainer container = builder.Build();

    Assert.That(container.Resolve<ICommand<SaveCommandData>>(), Is.InstanceOf<SaveCommand>());
    Assert.That(container.Resolve<ICommand<DeleteCommandData>>(), Is.InstanceOf<DeleteCommand>());
}

In addition to the types I used for unit testing in the previous post, there are two new types used for the testing of open generic classes.

/// <summary>
/// An abstract open generic base class.
/// </summary>
public abstract class Message<T>
{
}

/// <summary>
/// A class that closed the open generic type.
/// </summary>
public class StringMessage : Message<string>
{
}

The new message types are used in the next unit test to make sure that support for open generic classes is working.

[Test]
public void RegisterClosedTypesOf_OpenGenericAbstractClassTypeProvided_ClosingGenericTypesRegistered()
{
    ContainerBuilder builder = new ContainerBuilder();
    Assembly assembly = typeof(Message<>).Assembly;
    builder.RegisterClosedTypesOf(typeof(Message<>), assembly);
    IContainer container = builder.Build();

    Assert.That(container.Resolve<Message<string>>(), Is.InstanceOf<StringMessage>());
}

Now that we know how the extension method is used we can move onto the implementation.

/// <summary>
/// Extension methods for the <see cref="ContainerBuilder"/> class.
/// </summary>
public static class ContainerBuilderExtensions
{
    /// <summary>
    /// Scans the types in an assembly and registers those that support any base or interface that closes the 
    /// provided open generic service type.
    /// </summary>
    /// <param name="builder">The container builder being extended.</param>
    /// <param name="openGenericServiceType">The open generic interface or base class type for which implementations will be found.</param>
    /// <param name="assembly">The assembly to scan for the matching types.</param>
    public static void RegisterClosedTypesOf(this ContainerBuilder builder, Type openGenericServiceType, Assembly assembly)
    {
        if (openGenericServiceType == null) throw new ArgumentNullException("openGenericServiceType");

        if (!(openGenericServiceType.IsGenericTypeDefinition || openGenericServiceType.ContainsGenericParameters))
        {
            throw new ArgumentException(
                string.Format("The type '{0}' is not an open generic class or interface type.",
                              openGenericServiceType.FullName));
        }

        foreach (Type candidateType in assembly.GetTypes())
        {
            Type closedServiceType;
            if (findAssignableTypeThatCloses(candidateType, openGenericServiceType, out closedServiceType))
            {
                builder.Register(candidateType).As(closedServiceType);
            }
        }
    }

    /// <summary>
    /// Looks for an interface on the candidate type that closes the provided open generic interface type.
    /// </summary>
    /// <param name="candidateType">The type that is being checked for the interface.</param>
    /// <param name="openGenericServiceType">The open generic service type to locate.</param>
    /// <param name="closedServiceType">The type of the closed service if found.</param>
    /// <returns>True if a closed implementation was found; otherwise false.</returns>
    private static bool findAssignableTypeThatCloses(Type candidateType, Type openGenericServiceType, out Type closedServiceType)
    {
        closedServiceType = null;

        if (candidateType.IsAbstract) return false;

        foreach (Type interfaceType in getTypesAssignableFrom(candidateType))
        {
            if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == openGenericServiceType)
            {
                closedServiceType = interfaceType;
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// Returns the interface and base types that given a type is assignable from.
    /// </summary>
    /// <param name="candidateType">The type to find assignable types for.</param>
    /// <returns>A list of the assignable interface and base types.</returns>
    private static IEnumerable<Type> getTypesAssignableFrom(Type candidateType)
    {
        foreach (Type interfaceType in candidateType.GetInterfaces())
        {
            yield return interfaceType;
        }

        Type nextType = candidateType;
        while (nextType != typeof(object))
        {
            yield return nextType;
            nextType = nextType.BaseType;
        }
    }
}

After the usual sort of argument checking the types in the assembly are enumerated and tested to see if they close the open generic type. The findAssignableTypeThatCloses method does the work of locating a possible match and returns a value indicating if a match was found. When a match is found the out parameter is assigned the closing type that was located, and the registration is added to the ContainerBuilder. The getTypesAssignableFrom method helps out by returning all the interface and base types assignable from the type it is provided.

That is all that is needed to add support for open generic types in Autofac 1.4.

ContainerBuilderExtensions.cs (3.71 kb)

ContainerBuilderExtensionsTests.cs (3.93 kb)

Tags:

Categories: Garage Sale Code | Microsoft .NET

ReSharper 5.0 Beta available

by Alex Meyer-Gleaves 23 December 2009 - 12:24 PM

JetBrains has provided developers with an early Christmas present releasing the ReSharper 5.0 Beta on Christmas Eve. It looks there are plenty of new features to take for a test drive.

ReSharper 5.0 Beta introduces a great web development feature set; code analysis extended with call tracking, value tracking, and foreach-to-LINQ transformations; project-level refactorings; and a lot more enjoyable features.

The Beta version will work with both Visual Studio 2010 and Visual Studio 2008, although according to this post from JetBrains there are a number of known issues causing problems with support for Visual Studio 2010 Beta 2.

However, keep in mind that Visual Studio 2010 Beta 2 has a number of known issues that in certain scenarios prevent ReSharper from working well. Don’t worry too much though: it doesn’t mean your Visual Studio crashes every time you press Alt+Enter! JetBrains and Microsoft engineers are aware of the problems and working together to solve them by the time Visual Studio 2010 goes RTM.

Head on over to the What's New in ReSharper 5.0 Beta page for a download link and more information on the new features.

Tags:

Categories: Development Tools

Is64BitOperatingSystem and Is64BitProcess in .NET 4.0

by Alex Meyer-Gleaves 21 December 2009 - 12:07 AM

The Environment class in .NET 4.0 contains two new static properties for checking bitness: Is64BitOperatingSystem and Is64BitProcess. In the past I have had to answer these questions in code and wondered how the new properties ended up being implemented. It turns out that the code is actually quite elegant and simple to follow. They have taken advantage of the fact that there are two versions of the mscorlib.dll assembly: one for the x86 version of the framework and another for the x64 version.

The code in the 64-bit version of mscorlib.dll is really simple. If the 64-bit version is loaded, you must be running in a 64-bit process. And if your running in a 64-bit process, you must be running on a 64-bit version of Windows.

public static bool Is64BitOperatingSystem
{
    [SecuritySafeCritical]
    get
    {
        return true;
    }
}

public static bool Is64BitProcess
{
    get
    {
        return true;
    }
}

The code in the 32-bit version of mscorlib.dll is almost as simple. If the 32-bit version is loaded, you must be running in a 32-bit process. In this case though it does not automatically mean you are running on a 32-bit version of Windows. It is possible that the process is running under the WOW64 (Windows-on-Windows 64-bit) subsystem on a 64-bit version of Windows.

The IsWow64Process function is used to determine if the process is running under WOW64. When this returns true you must be running on a 64-bit version of Windows because your process is running under the WOW64 subsystem. It is worth noting that the IsWow64Process function in kernel32.dll is present in current 32-bit versions of Windows but you need to check for its existence to maintain compatibility with versions where it is not present.

public static bool Is64BitOperatingSystem
{
    [SecuritySafeCritical]
    get
    {
        bool flag;
        return ((Win32Native.DoesWin32MethodExist("kernel32.dll", "IsWow64Process") 
            && Win32Native.IsWow64Process(Win32Native.GetCurrentProcess(), out flag)) && flag);
    }
}

public static bool Is64BitProcess
{
    get
    {
        return false;
    }
}

I really like the implementation; it is easy to follow and reliable. You will no longer need for check the IntPtr.Size value that gets hardcoded into mscorlib.dll to determine the bitness of your process, and you wont have to write your own platform invoke code to check the bitness of the operating system either. What joy a couple of simple static properties can bring!

Tags:

Categories: Microsoft .NET

Registering open generic interface types in Autofac

by Alex Meyer-Gleaves 19 December 2009 - 7:22 PM

UPDATE (22 December 2009): I have submitted a patch to Nick and this feature has now been added to the Autofac V2 codebase. While including the patch Nick added support for open generic classes and renamed the extension method to AsClosedTypesOf. This post will be left in its current form and remains a valid example of extending Autofac.

There has been some discussion lately around connecting an open generic type to its implementation types in a number of different dependency injection containers including StructureMap and Unity:

It looks like this is not the first time this scenario has been discussed:

I also recently noticed a posting on the Autofac Google Group asking if it was possible for Autofac to automatically register an open generic interface type against its implementations. Nicholas Blumhardt (the creator of Autofac and all round nice guy) suggested that this would be easy to implement using the new RegisterAssemblyTypes method found on the ContainerBuilder in the upcoming V2 release. Since I have been meaning to take a closer look at the preview of Autofac V2, I decided that having a look into solving this would be a good way for me to dip my toes into the water. I decided to limit the scope to supporting only automatic registrations for open generic interface types. There is no doubt you could use the extensibility provided by the RegisterAssemblyTypes method to take things much further and add features like those supported in the Unity Auto Registration library.

Time to introduce some types that will be used in the unit tests. First is the open generic interface type.

/// <summary>
/// An open generic interface type.
/// </summary>
public interface ICommand<T>
{
    void Execute(T data);
}

Next we have a couple of simple types that will be used as the generic type parameters.

/// <summary>
/// A type to use as a generic parameter.
/// </summary>
public class SaveCommandData
{
}

/// <summary>
/// A type to use as a generic parameter.
/// </summary>
public class DeleteCommandData
{
}

To keep things interesting I decided to include an abstract base class that implements the ICommand interface.

/// <summary>
/// An abstract base class that implements the open generic 
/// interface type.
/// </summary>
public abstract class CommandBase<T> : ICommand<T>
{
    public abstract void Execute(T data);
}

There will be two command implementations. The first will directly implement the ICommand interface.

/// <summary>
/// A command class that directly implements the open 
/// generic interface type.
/// </summary>
public class SaveCommand : ICommand<SaveCommandData>
{
    public void Execute(SaveCommandData data)
    {
    }
}

The second will implement the ICommand interface by inheriting from the CommandBase<T> abstract class.

/// <summary>
/// A command class that implements the open generic interface 
/// type by inheriting from the abstract base class.
/// </summary>
public class DeleteCommand : CommandBase<DeleteCommandData>
{
    public override void Execute(DeleteCommandData data)
    {
    }
}

I will use the first unit test to define the name and signature of the extension method that be will added to the RegistrationBuilder. The extension method will be named WhereTypeClosesOpenGenericInterface and will be available on the RegistrationBuilder returned from the RegisterAssemblyTypes method. It will take a single parameter for the Type that represents the open generic interface type that automatic registrations will be created for.

This first unit test will actually ensure that passing a null value as the method parameter will result in an ArgumentNullException being thrown.

[Test]
public void WhereTypeClosesOpenGenericInterface_NullTypeProvided_ThrowsException()
{
    ContainerBuilder builder = new ContainerBuilder();
    Assert.Throws<ArgumentNullException>(() => builder.RegisterAssemblyTypes(typeof(ICommand<>).Assembly).
        WhereTypeClosesOpenGenericInterface(null));
}

The next unit test will ensure that passing a non-generic type into the method will result in an ArgumentException being thrown.

[Test]
public void WhereTypeClosesOpenGenericInterface_NonGenericTypeProvided_ThrowsException()
{
    ContainerBuilder builder = new ContainerBuilder();
    Assert.Throws<ArgumentException>(() => builder.RegisterAssemblyTypes(typeof(ICommand<>).Assembly).
        WhereTypeClosesOpenGenericInterface(typeof(SaveCommandData)));
}

Another simple unit test will ensure that passing in a closed generic type will also result in an ArgumentException being thrown.

[Test]
public void WhereTypeClosesOpenGenericInterface_ClosedGenericTypeProvided_ThrowsException()
{
    ContainerBuilder builder = new ContainerBuilder();
    Assert.Throws<ArgumentException>(() => builder.RegisterAssemblyTypes(typeof(ICommand<>).Assembly).
        WhereTypeClosesOpenGenericInterface(typeof(ICommand<SaveCommandData>)));
}

The last of the boring unit tests ensures that passing in an open generic type that is not an interface will again result in an ArgumentException being thrown.

[Test]
public void WhereTypeClosesOpenGenericInterface_NonInterfaceOpenGenericTypeProvided_ThrowsException()
{
    ContainerBuilder builder = new ContainerBuilder();
    Assert.Throws<ArgumentException>(() => builder.RegisterAssemblyTypes(typeof(ICommand<>).Assembly).
        WhereTypeClosesOpenGenericInterface(typeof(List<>)));
}

Now onto the interesting unit test that will ensure our registrations are wired up correctly. We use our new WhereTypeClosesOpenGenericInterface extension method and pass it the ICommand<> open generic interface type. Obviously when we resolve a closed generic interface type we except the returned instance to be the type that implements it. In the case of the SaveCommand the implementation of the interface is direct, and with the DeleteCommand the implementation of the interface is through its inheritance of CommandBase<T>.

[Test]
public void WhereTypeClosesOpenGenericInterface_OpenGenericInterfaceTypeProvided_ClosingGenericTypesRegistered()
{
    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterAssemblyTypes(typeof(ICommand<>).Assembly)
        .WhereTypeClosesOpenGenericInterface(typeof(ICommand<>));
    IContainer container = builder.Build();

    Assert.That(container.Resolve<ICommand<SaveCommandData>>(), Is.TypeOf<SaveCommand>());
    Assert.That(container.Resolve<ICommand<DeleteCommandData>>(), Is.TypeOf<DeleteCommand>());
}

Finally we arrive at the implementation code. I looked at the StructureMap implementation before writing this to keep an eye out for details that I might have otherwise forgotten. Doing so seemed like a good idea considering their code has already been put through its paces. Take a quick look over the code and I will explain what is going on below.

/// <summary>
/// Extension methods for the <see cref="RegistrationBuilder{TLimit,TActivatorData,TRegistrationStyle}"/> class.
/// </summary>
public static class RegistrationBuilderExtensions
{
    /// <summary>
    /// Specifies that a type from a scanned assembly is registered if it implements an interface
    /// that closes the provided open generic interface type.
    /// </summary>
    /// <typeparam name="TLimit">Registration limit type.</typeparam>
    /// <typeparam name="TRegistrationStyle">Registration style.</typeparam>
    /// <typeparam name="TScanningActivatorData">Activator data type.</typeparam>
    /// <param name="registration">Registration to set service mapping on.</param>
    /// <param name="openGenericInterfaceType">The open generic interface type for which implementations will be found.</param>
    /// <returns>Registration builder allowing the registration to be configured.</returns>
    public static RegistrationBuilder<TLimit, TScanningActivatorData, TRegistrationStyle>
        WhereTypeClosesOpenGenericInterface<TLimit, TScanningActivatorData, TRegistrationStyle>(
            this RegistrationBuilder<TLimit, TScanningActivatorData, TRegistrationStyle> registration, Type openGenericInterfaceType)
        where TScanningActivatorData : ScanningActivatorData
    {
        if (openGenericInterfaceType == null)
        {
            throw new ArgumentNullException("openGenericInterfaceType");
        }

        if (!(openGenericInterfaceType.IsGenericTypeDefinition || openGenericInterfaceType.ContainsGenericParameters) || !openGenericInterfaceType.IsInterface)
        {
            throw new ArgumentException("The type '" + openGenericInterfaceType.FullName + "' is not an open generic interface type.");
        }

        return registration.Where(candidateType => findInterfaceThatCloses(candidateType, openGenericInterfaceType) != null)
            .As(candidateType => findInterfaceThatCloses(candidateType, openGenericInterfaceType));
    }

    /// <summary>
    /// Looks for an interface on the candidate type that closes the provided open generic interface type.
    /// </summary>
    /// <param name="candidateType">The type that is being checked for the interface.</param>
    /// <param name="openGenericInterfaceType">The open generic interface type to locate.</param>
    /// <returns>The type of the interface if found; otherwise, <c>null</c>.</returns>
    private static Type findInterfaceThatCloses(Type candidateType, Type openGenericInterfaceType)
    {
        if (candidateType.IsAbstract) return null;

        foreach (Type interfaceType in candidateType.GetInterfaces())
        {
            if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == openGenericInterfaceType)
            {
                return interfaceType;
            }
        }

        return (candidateType.BaseType == typeof(object)) 
            ? null
            : findInterfaceThatCloses(candidateType.BaseType, openGenericInterfaceType);
    }
}

First the parameter for the open generic interface type is checked to ensure that it is not null and that it is indeed an open generic interface type. Next we use the RegistrationBuilder instance that is being extended to determine what types we want registered and what their service mappings will be. The important methods on the RegistrationBuilder that enable this are the Where and As methods. The Where method takes a predicate that is used to filter the list of scanned types down to only those you are interested in registering. The As method is used to provide the service mappings for the types that got included for registration after the filter was applied.

The Func<Type,bool> predicate provided to the Where method on the RegistrationBuilder instance utilizes a private method named findInterfaceThatCloses. When the findInterfaceThatCloses method is called it will look for an interface on the type provided as the first parameter, that matches the type provided as the second parameter. In our case we are passing in the candidate type that was provided by the assembly scanning process, and the open generic interface type we are interested in matching. When no matching interface is found null is returned. When used in the delegate parameter provided to the Where method for filtering we check for the return from findInterfaceThatCloses being not null, and use the actual type returned from the method for the delegate parameter provided to the As method for mapping the services. We know that when the As method is called it will only be provided with types that were included by the filter, so we need not worry about receiving a type that does not implement the interface at this point.

The implementation of the findInterfaceThatCloses method ensures that only types which are not abstract are checked for matching interfaces. It then iterates through the available interfaces and checks if any match the open generic interface type provided. If no matching interface is found we recursively check if the type’s base class implements the interface until we reach a type that inherits directly from object.

As you can see Nick has done a great job making Autofac extensible, allowing additional requirements for your container to be met with very little effort on your part. I think the next version of Autofac is shaping up nicely and I look forward to posting more about it in the future.

Tags:

Categories: Garage Sale Code | Microsoft .NET

About the author

Alex Meyer-Gleaves I'm a software developer living in Australia (that island like continent in the southern hemisphere). I love Microsoft .NET and C#. I hate early mornings, slow drivers and Lotus Notes.

Google Reader Clips

SpringWidgets
RSS Reader
This widget is the staple of our platform. Read all your feeds right here with thisone widget - Supported feeds are OPML, RSS, RDF, ATOM. Watch your favorite Podcastin the embedded Video Player on the Desktop or publish your own video playlist toyour site for others to view!

Recent Comments

Comment RSS

Links

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in  anyway.

© Copyright 2008