Monday, November 24, 2014

Nancy shared module

I was recently involved in development of a new system that heavily uses NancyFX as Rest API framework. System has a couple of different rest APIs. At some point we decided to show somehow a version of each service and since we have around 10 different services, it'd be nice to have some shared functionality. Our solution is quite simple, we created a new solution with class library inside, added NancyFX as a dependency using Nuget and added one new class VersionModule:


public class VersionModule : NancyModule
{
    public VersionModule() : base("/version")
    {
        Get["/"] = _ => Response.AsJson(new {Text = "Here shoul be some usefull info"});
    }
}

If we create a nuget package or just link this assembly from any application thta is NancyFX based rest api we will get automatically the new endpoint '/version'.

To make it useful let's try to return the version of the service which host our module. It's a bit complicated, after checking different posts on stack overflow and other resources I didn't find anything that works for me. So we created a new assembly attribute and a new exception:


[AttributeUsage(AttributeTargets.Assembly)]
class RootAssemblyAttribute : Attribute
{
}




public class RootAssemblyNotFoundException : Exception
{
    public RootAssemblyNotFoundException()
    {
    }

    public RootAssemblyNotFoundException(string message) : base(message)
    {
    }

    public RootAssemblyNotFoundException(string message, Exception innerException) : base(message, innerException)
    {
    }

    protected RootAssemblyNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
    {
    }
}

I'ts just a way to mark assembly as one that represents rest api and contains rest api version.
On order to make it work we need to change AssemblyInfo.cs file of main assembly and add in that file new row:


[assembly: RootAssemblyAttribute]

Now we need to adjust a bit VersionModule:


public VersionModule() : base("/version")
{
    Get["/"] = _ =>
    {
        var rootAssembly = AppDomain.CurrentDomain.GetAssemblies()
            .FirstOrDefault(a => a.GetCustomAttributes(typeof (RootAssemblyAttribute), false).Any());

        if (rootAssembly == null)
        {
            return new RootAssemblyNotFoundException("One of assemblies has to be marked as Root assembly");
        }

        return Response.AsJson(new {Verson = rootAssembly.GetName().Version});
    };
}