July 2011


.Net Development28 Jul 2011 08:18 pm

The Castle Project has a great logging integration facility that lets you integrate Log4Net (or NLog) into your dependency resolution such that if you declare a dependency on ILogger (Castles wrapper around Log4Net.ILog), the dependancy that gets injected is initialized with the type into which it is being injected. If you understand how Log4Net logger names work, you’ll know why this is important.

But on my current project, I am not using Castle; I am using Microsoft’s Unity IoC container. Figuring out how to do the same thing in Unity took me most of a day and I didn’t like my solution, so I posted a question on Stack Overflow and got a response that pointed me to exactly what I wanted. The links were to a blog post and ultimately to an obscure thread on the Unity – Patern’s and Practices forum. I find that forums are notorious for not being there for the long haul, and the blog did not provide any details on its own, so I am re-posting it it all here in a slightly cleaned up form for posterity’s sake.

Implementing this in Unity requires three steps.

  1. Creating a Build Tracking Extension
  2. Creating a Logger Creation Extension
  3. Wire the extensions into Unity

The Build Tracking Extension

The first step is to a create Unity extension that installs a build tracking strategy. This strategy uses a policy to keep track of the stack of dependencies being built as part of handling the current resolution request. This is needed so that when resolving the logger dependency, we can consult the stack to see what type the dependency is being resolved for.

Here is the code, pretty much taken straight from the aforementioned post.

using System;
using System.Collections.Generic;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.ObjectBuilder;
 
public class BuildTracking : UnityContainerExtension
{
 
    protected override void Initialize()
    {
        Context.Strategies.AddNew<BuildTrackingStrategy>(UnityBuildStage.TypeMapping);
    }
 
    public static IBuildTrackingPolicy GetPolicy(IBuilderContext context)
    {
        return context.Policies.Get<IBuildTrackingPolicy>(context.BuildKey, true);
    }
 
    public static IBuildTrackingPolicy SetPolicy(IBuilderContext context)
    {
        IBuildTrackingPolicy policy = new BuildTrackingPolicy();
        context.Policies.SetDefault(policy);
        return policy;
    }
}
 
public class BuildTrackingStrategy : BuilderStrategy
{
 
    public override void PreBuildUp(IBuilderContext context)
    {
        var policy = BuildTracking.GetPolicy(context)
            ?? BuildTracking.SetPolicy(context);
 
        policy.BuildKeys.Push(context.BuildKey);
    }
 
    public override void PostBuildUp(IBuilderContext context)
    {
        IBuildTrackingPolicy policy = BuildTracking.GetPolicy(context);
        if ((policy != null) && (policy.BuildKeys.Count > 0))
        {
            policy.BuildKeys.Pop();
        }
    }
}
 
public interface IBuildTrackingPolicy : IBuilderPolicy
{
    Stack<object> BuildKeys { get; }
}
 
public class BuildTrackingPolicy : IBuildTrackingPolicy
{
 
    public BuildTrackingPolicy()
    {
        BuildKeys = new Stack<object>();
    }
 
    public Stack<object> BuildKeys { get; private set; }
}

The Logger Creation Extension

With the build tracking extension in place, it is now possible to create a logger creation extension that will use it to create an instance of ILog. (This implemenation is not generic like the Castle implemenation but specific to Log4Net).

Again here is the code, pretty much straight from the forum thread. All I have done is incorporated the patch (also from the thread) to handle direct resolution requests for an ILog instance.

using System;
using System.Diagnostics;
using System.Linq;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.ObjectBuilder;
using Log4Net;
 
public class LogCreation : UnityContainerExtension
{
 
    protected override void Initialize()
    {
        Context.Strategies.AddNew<LogCreationStrategy>(UnityBuildStage.PreCreation);
    }
}
 
public class LogCreationStrategy : BuilderStrategy
{
 
    public bool IsPolicySet { get; private set; }
 
    public override void PreBuildUp(IBuilderContext context)
    {
        Type typeToBuild = context.BuildKey.Type;
        if (typeof(ILog).Equals(typeToBuild))
        {
 
            if (context.Policies.Get<IBuildPlanPolicy>(context.BuildKey) == null)
            {
                Type typeForLog = LogCreationStrategy.GetLogType(context);
                IBuildPlanPolicy policy = new LogBuildPlanPolicy(typeForLog);
                context.Policies.Set<IBuildPlanPolicy>(policy, context.BuildKey);
 
                IsPolicySet = true;
            }
        }
    }
 
    public override void PostBuildUp(IBuilderContext context)
    {
        if (IsPolicySet)
        {
            context.Policies.Clear<IBuildPlanPolicy>(context.BuildKey);
            IsPolicySet = false;
        }
    }
 
    private static Type GetLogType(IBuilderContext context)
    {
        Type logType = null ;  
        IBuildTrackingPolicy buildTrackingPolicy = BuildTracking.GetPolicy(context);
        if ((buildTrackingPolicy != null) && (buildTrackingPolicy.BuildKeys.Count >= 2))
        {
            logType = ((NamedTypeBuildKey)buildTrackingPolicy.BuildKeys.ElementAt(1)).Type;
        }
        else
        {
            StackTrace stackTrace = new StackTrace();
            //first two are in the log creation strategy, can skip over them
            for (int i = 2; i < stackTrace.FrameCount; i++)
            {
                StackFrame frame = stackTrace.GetFrame(i);
                logType = frame.GetMethod().DeclaringType;
                if (!logType.FullName.StartsWith("Microsoft.Practices"))
                {
                    break;
                }
            }
        }
        return logType;
    }
}
 
public class LogBuildPlanPolicy : IBuildPlanPolicy
{
 
    public LogBuildPlanPolicy(Type logType)
    {
        LogType = logType;
    }
 
    public Type LogType { get; private set; }
 
    public void BuildUp(IBuilderContext context)
    {
        if (context.Existing == null)
        {
            ILog log = LogManager.GetLogger(LogType);
            context.Existing = log;
        }
    }
}

Wiring It All Up

Lastly, to wire this up to your container all you need is the following (also stolen) code:

var container = new UnityContainer()
    .AddNewExtension<BuildTracking>()
    .AddNewExtension<LogCreation>()
    .Register<MyClassWithLoggerDependency>();
 
var myClass = container.Resolve<MyClassWithLoggerDependency>();
 
//Or
var myLogger = container.Resolve<ILog>();  //return logger with a name of this.GetType().Fullname

Hope this code helps you as much as it did me. Many thanks to wageoghe, David Keaveny, Marco and Scott!

.Net Development19 Jul 2011 08:39 pm

If you are doing low level TCP networking in .Net and in particular are using a TcpListener on a client to listen for callbacks form a server, you need to select a port on which to listen. Typically, in this scenario, you don’t want to have to specify a port in the .config file. You just want to pick any open port (well actually, any open port, in the IANA private port range).

After looking around the net, I found some almost correct but not quite code for this, so I though I should post my improved version here.

The below function will return the first open port in the IANA port range that is not currently being used on the local machine.

Be careful however. Just because the port is not used at the point the code is called, doesn’t mean it won’t be in use when you go to open your listener. Just incase some other process grabbed the port in the interim, you should always open your listener in a try catch block and if the call fails because the port is in use, grab another available port and try again.

private static int SelectAvailablePort()
{
    const int START_OF_IANA_PRIVATE_PORT_RANGE = 49152;
    var ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
    var tcpListeners = ipGlobalProperties.GetActiveTcpListeners();
    var tcpConnections = ipGlobalProperties.GetActiveTcpConnections();
 
    var allInUseTcpPorts = tcpListeners.Select(tcpl => tcpl.Port)
        .Union(tcpConnections.Select(tcpi => tcpi.LocalEndPoint.Port));
 
    var orderedListOfPrivateInUseTcpPorts = allInUseTcpPorts
        .Where(p => p >= START_OF_IANA_PRIVATE_PORT_RANGE)
        .OrderBy(p => p);
 
    var candidatePort = START_OF_IANA_PRIVATE_PORT_RANGE;
    foreach (var usedPort in orderedListOfPrivateInUseTcpPorts)
    {
        if (usedPort != candidatePort) break;
        candidatePort++;
    }
    return candidatePort;
}

Disclaimer: I am by no means an network programming guru. If you find issues with this snippet or have a better one, please let me know.