Thursday, August 27, 2015

IEnumerable Unity Injection

A few years ago I blogged about how to add Lazy Unity Injection, and then a year after that Unity 3 added that feature. Recently I had to dust off this old code to do something similar...

I wanted to use Unity to inject a collection of registered types into one of my services. To do this directly from the container you would use named registrations and ResolveAll. However if you just try to resolve an IEnumerable of a type in a constructor, then Unity will just try to use Resolve and thus throw an InvalidOperationException.

We can easily "fix" this by registering an extension with our container.

Extension

public class EnumerableContainerExtension : UnityContainerExtension
{
    protected override void Initialize()
    {
        Context.Policies.Set<IBuildPlanPolicy>(
            new EnumerableBuildPlanPolicy(),
            typeof(IEnumerable<>));
    }
 
    private class EnumerableBuildPlanPolicy : IBuildPlanPolicy
    {
        public void BuildUp(IBuilderContext context)
        {
            if (context.Existing != null)
                return;
 
            var container = context.NewBuildUp<IUnityContainer>();
            var typeToBuild = context.BuildKey.Type.GetGenericArguments()[0];
 
            context.Existing = container.ResolveAll(typeToBuild);
 
            DynamicMethodConstructorStrategy.SetPerBuildSingleton(context);
        }
    }
}

Saturday, August 22, 2015

Ambiguous Invocation from Optional Parameter Overloads

There are many reasons for your C# compiler to give you an ambiguous invocation error. When using optional arguments you have to be sure not to create an overload that have overlapping optional parameters. Let's take a look:

public void DoStuff(int i, object o = null) { }
 
public void DoStuff(int i, string s = null) { }
 
public void DoStuff(int i, string s = null, bool b = false) { }
 
public void Test()
{
    // Ambiguous invocation!
    DoStuff(1);
}

There is no need to create methods like the ones shown above!

Instead consider that there is no reason to have two overloads being called with the potentially the same parameters. Such overloads should be combine into one method, and other overloads with different types argument can just be written as normal parameters without default values. Again, let's take a look:

public void DoStuff(int i, object o) { }
 
public void DoStuff(int i, string s = null, bool b = false) { }
 
public void Test()
{
    // No more ambiguous invocation :)
    DoStuff(1);
}

I hope that helps,
Tom

Saturday, August 15, 2015

Create objects from default constructor

Do you think that title sound redundant? If so, which method were you thinking of? Because there are several! Let's talk about those...and be sure to scroll to the bottom for a performance comparison!

Sample Class

Here is the class that we will be instantiating in our tests.

internal class TestClass
{
    public Guid Guid { get; private set; }
 
    public TestClass()
    {
        Guid = Guid.NewGuid();
    }
}

The new Keyword

This is the obviously, easier, fastest, normal way of instantiating an object...obviously.

[Fact]
public void NewDuh()
{
    var testObject = new TestClass();
    Assert.NotNull(testObject.Guid);
}

Activator.CreateInstance

This is a very simple and common way to instantiate an object from a Type object. It has an overload that takes a params object collection to let you use other, non default, constructors.

[Fact]
public void ActivatorCreateInstance()
{
    var type = typeof (TestClass);
    var instance = Activator.CreateInstance(type);
            
    var testObject = Assert.IsType<TestClass>(instance);
    Assert.NotNull(testObject.Guid);
}

Saturday, July 25, 2015

Cascading AppSettings from Multiple Config Files

In my previous blog post I talked about creating complex configuration objects from AppSettings. I really like this practice, but it can cause your config files to grow pretty large. One solution is to break your app.config into multiple files using the SectionInformation.ConfigSource property.

This also has the added side effect of allowing you to include defaults and overrides by having those settings cascade. I have created an extension method to combine a series of NameValueCollections, such as an AppSettings section. You can also grab this code from the GitHub project.

Combine Extension

public static NameValueCollection Combine(
    this NameValueCollection collection, 
    params NameValueCollection[] collections)
{
    var result = new NameValueCollection { collection };
 
    foreach (var subCollection in collections)
        foreach (var key in subCollection.AllKeys)
        {
            if (result.AllKeys.Contains(key))
                continue;
 
            var value = subCollection[key];
            result.Add(key, value);
        }
 
    return result;
}

Sunday, July 19, 2015

Create Config Objects from AppSettings

Providing configuration settings is a vital task that all applications need. Unfortunately dealing with ConfigurationSections and IConfigurationSectionHandlers can be annoying.

That is why I created a simple little extension method to create complex objects from your app settings. The extension works with a NameValueCollection, and can create primitive types, complex objects, collections, dictionaries, and even recursive properties.

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="TestConfig.Int" value="1" />
    <add key="TestConfig.String" value="Hello" />
    <add key="TestConfig.DateTime" value="1/2/2015" />
    <add key="TestConfig.TimeSpan" value="00:01:00" />
    <add key="TestConfig.Enum" value="Moon" />
    <add key="TestConfig.NullableIntA" value="2" />
    <add key="TestConfig.NullableIntB" value="" />
  </appSettings>
</configuration>

Test

[Fact]
public void CreateSimpleObject()
{
    var result = ConfigurationManager.AppSettings.CreateObject<TestConfig>();
 
    Assert.NotNull(result);
    Assert.Equal(1, result.Int);
    Assert.Equal(42, result.IntWithDefault);
    Assert.Equal("Hello", result.String);
    Assert.Equal(new DateTime(2015, 1, 2), result.DateTime);
    Assert.Equal(TimeSpan.FromMinutes(1), result.TimeSpan);
    Assert.Equal(TestEnum.Moon, result.Enum);
    Assert.Equal(2, result.NullableIntA);
    Assert.Null(result.NullableIntB);
}

Enjoy,
Tom

Saturday, July 11, 2015

Common.Logging.NLog40

The Common.Logging team accepted my pull request, and there is now a Common.Logging.NLog40 package to support NLog 4.

Enjoy,
Tom

Sunday, June 28, 2015

.NET Asynchronous Batch Processor

The .NET Framework offers a series of Thread-Safe Collections that allows you to consume collections across threads. Processing the contents of these collections still requires a thread, and while there is a BlockingCollection there is unfortunately no such class to support this in an asynchronous fashion. (Please note that the always awesome Stephen Cleary did actually implement an AsyncCollection.)

What if you want to handle dynamically sized batches of data in an asynchronous manner?

You could use a series of Dataflow blocks, or if you are looking for a simple solution you can write a small class that uses an async loop to process a ConcurrentQueue. Below is an abstract base class that can help you implement this:

Base Class

public abstract class BatchProcessorBase<T> : IDisposable
{
    protected readonly int MaxBatchSize;
    private readonly ConcurrentQueue<T> _queue;
    private readonly CancellationTokenSource _cancelSource;
    private readonly object _queueTaskLock;
    private Task _queueTask;
    private bool _isDiposed;
 
    protected BatchProcessorBase(int maxBatchSize)
    {
        MaxBatchSize = maxBatchSize;
        _queue = new ConcurrentQueue<T>();
        _cancelSource = new CancellationTokenSource();
        _queueTaskLock = new object();
        _queueTask = Task.FromResult(true);
    }
        
    public void Enqueue(T item)
    {
        _queue.Enqueue(item);
        TryStartProcessLoop();
    }
 
    public void Dispose()
    {
        if (_isDiposed)
            return;
 
        _cancelSource.Cancel();
        _isDiposed = true;
    }
 
    protected abstract Task ProcessBatchAsync(
        IList<T> list, 
        CancellationToken cancelToken);
 
    private void TryStartProcessLoop()
    {
        // Lock so only one thread can manipulate the queue task.
        lock (_queueTaskLock)
        {
            // If cancellationhas been requested, do not start.
            if (_cancelSource.IsCancellationRequested)
                return;
 
            // If the loop is still active, do not start.
            if (!_queueTask.IsCompleted)
                return;
 
            // If the queue is empty, do not start.
            if (_queue.Count == 0)
                return;
 
            // Start a new task to process the queue.
            _queueTask = Task.Run(() => ProcessQueue(), _cancelSource.Token);
 
            // When the process queue task completes, check to see if
            // the queue has been populated again and needs to restart.
            _queueTask.ContinueWith(t => TryStartProcessLoop());
        }
    }
 
    private async Task ProcessQueue()
    {
        // Stay alive until the queue is empty or cancellation is requested.
        while (!_cancelSource.IsCancellationRequested && _queue.Count > 0)
        {
            var list = new List<T>();
            T item;
 
            // Dequeue up to a full batch from the queue.
            while (list.Count < MaxBatchSize && _queue.TryDequeue(out item))
                list.Add(item);
 
            // Process the dequeued items.
            await ProcessBatchAsync(list, _cancelSource.Token);
        }
    }
}
Real Time Web Analytics