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);
        }
    }
}

Wednesday, June 24, 2015

Capture xUnit Test Output with NLog and Common Logging

I recently blogged about How To Capture Test Output in xUnit 2.0. This is great, but how can we pass the ITestOutputHelper into our code to capture log output?

You could just wrap the xUnit helper in an ILog or ILogger, but we can also take it a step further and get all of the NLog features too! By creating an NLog target that wraps the ITestOutputHelper we can enable ourselves to use multiple targets, layouts, variables, verbosity levels, and more.

Sample Unit Test

public class NLogTests : IDisposable
{
    private readonly ILogger _logger;
 
    public NLogTests(ITestOutputHelper outputHelper)
    {
        _logger = outputHelper.GetNLogLogger();
    }
 
    public void Dispose()
    {
        _logger.RemoveTestOutputHelper();
    }
 
    [Fact]
    public void Hello()
    {
        _logger.Trace("World Trace");
        _logger.Debug("World Debug");
        _logger.Warn("World Warn");
        _logger.Error("World Error");
    }
}

Monday, June 22, 2015

How To: Kill child process when parent process is killed

Killing child all child process spawned by a parent process is an extremely useful trick that is not directly supported by the .NET framework. Fortunately the windows operating system, more specifically Kernel32.dll, does support the ability to link one process to another on shutdown. A huge thanks to Matt Howell for sharing this solution on Stack Overflow!

I took the liberty of cleaning up a few small things in the code and creating a demo:

Saturday, May 30, 2015

.NET Generic Overloads: How to support T and IList

What happens when you want to overload a generic method where the first method accepts a single object and the other accepts an IList of that type?

It will only work when specifically try to pass in an IList. If you try to pass in a List it will fail because the compiler will identify the generic parameter overload and fail before trying to use the implicit cast to an IList.

This is because a C# compiler tries to identify overloaded methods it checks for matching parameters in the following order:

  1. Explicit type matches.
  2. Generic parameters.
  3. Implicit type matches.

Let's look at an example!

Example of what DOES NOT work.

public class OverloadSample1
{
    [Fact]
    public void Test()
    {
        // Matches Method A - Good
        ISample sample = new Sample();
        this.Method(sample);
 
        // Matches Method B - Good
        IList<ISample> samples1 = new List<ISample>();
        this.Method(samples1);
 
        // Matches Method A - BAD!
        List<ISample> samples2 = new List<ISample>();
        this.Method(samples2);
    }
 
    // A
    public void Method<T>(T sample)
        where T : ISample
    {
    }
 
    // B
    public void Method<T>(IList<T> sample)
        where T : ISample
    {
    }
}

...so, how do we solve this problem?

Real Time Web Analytics