Creating stronger value type contracts

I’ve long been annoyed that value types don’t have strong semantic information attached to them such that the compiler would barf if I try and pass an value type that isn’t semantically the same as what the function wanted. For example, what does the following signature mean other than than taking in 2 ints and returning a bool?

IsLoggedIn :: int -> int -> bool

What I’d really like the signature to look like is

IsLoggedIn :: UserId -> SessionId -> bool

In F# you can do this sort of with type aliases and augmenting the signature with the type information. However, its just editor magic, it doesn’t actually compile to anything that would stop you from accidentally calling a function with the arguments reversed. An int is an int is an int, right?

var userId = 1
var sessionId = 2

IsLoggedIn(sessionId, userId)

This is perfectly valid to the compiler and means you won’t catch it until its unit tested, peer reviewed (if everyone is paying attention), or found during runtime. I’d like to have this caught at compile time.

A solution

Instead, what if we wrapped important value types into their own structs? Something like this:

public struct UserId
{
    private readonly Int32 _int;

    private UserId(int @int)
    {
        _int = @int;
    }

    public static explicit operator UserId(int value)
    {
        return new UserId(value);
    }

    public static implicit operator int(UserId value)
    {
        return value._int;
    }
}

public struct SessionId
{
    private readonly Int32 _int;

    private SessionId(int @int)
    {
        _int = @int;
    }

    public static explicit operator SessionId(int value)
    {
        return new SessionId(value);
    }

    public static implicit operator int(SessionId value)
    {
        return value._int;
    }
}

Structurally its exactly the same as an int, and it doesn’t cost you anything to use it. But, now the compiler will fail if you try and pass this

strongtypes

Adding some meta data

Now there is a problem though of project boundaries. What I mean is when your data types go over the wire, either through webapi or wcf or to a DB or some other form. To make this actually useful we have to introduce a few more things to make it easy to be transparent through these edge cases.

First, lets augment the strong inheritance heirarchy. I have interfaces that look like:

public interface IStrongType<out T> : IAcceptStrongTypeVisitor
{
    T UnderlyingValue();        
}
public interface IInt32 : IStrongType<int>
{
    string ToString(string format);

    string ToString(string format, IFormatProvider provider);

    string ToString(IFormatProvider provider);
}
public interface IStrongTypeVistor<out TResult>
{        
    TResult Visit(IGuid data);
    TResult Visit(IInt32 data);
    TResult Visit(IInt64 data);
    TResult Visit(IFloat data);
    TResult Visit(IDouble data);
}

Now I can have strong types implement their corresponding value type interfaces (I want a strong int to have the same methods as a regular int) as well as visit on top of them.

Serializing JSON

The first order of business is serializing to and from JSON. To do that I’ve created a json converter that knows how to cast and get the underlying value of a strong type

public class PrimitiveJsonConverter<T> : JsonConverter
    where T : struct
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var underlying = (IStrongType<T>)(value);

        writer.WriteValue(underlying.UnderlyingValue());
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var data = serializer.Deserialize<T>(reader);

        return data.ExplicitCastTo(objectType);
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }
}

And a utility extension method to reflectively invoke the explicit cast operator on a type

public static object ExplicitCastTo(this object obj, Type type)
{
    var castOperator = type.GetMethod("op_Explicit", new[] { obj.GetType() });

    if (castOperator == null)
    {
        throw new InvalidCastException("Can't cast to " + type.Name);
    }

    return castOperator.Invoke(null, new[] { obj });
}

Now a strong type will actually look like this:

[Serializable]
[JsonConverter(typeof(IntCaster))]
public struct SessionId : IInt32
{
    private readonly Int32 _int;

    private SessionId(int @int)
    {
        _int = @int;
    }

    public static explicit operator SessionId(int value)
    {
        return new SessionId(value);
    }

    public static implicit operator int(SessionId value)
    {
        return value._int;
    }

    public int UnderlyingValue()
    {
        return _int;
    }

    public TResult Accept<TResult>(IStrongTypeVistor<TResult> visitor)
    {
        return visitor.Visit(this);
    }

    public override string ToString()
    {
        return _int.ToString();
    }

    public string ToString(string format)
    {
        return _int.ToString(format);
    }

    public string ToString(string format, IFormatProvider provider)
    {
        return _int.ToString(format, provider);
    }

    public string ToString(IFormatProvider provider)
    {
        return _int.ToString(provider);
    }
}

Handling WCF

For WCF I took a lazier approach. For my use case we can distribute an assembly that contains all the strong types and ask consumers to re-use the types when generating proxies. If they don’t, WCF will auto generate a type that boxes the result and send it to you anyways. It makes it more annoying for a consumer, but not impossible to use.

WebAPI parameter parsing

Web Api exposes a way to hook into the parameter/object binding as things come in over the wire. You just need to implement the HttpParameterBinding abstract class. Then you register the binder either as an attribute on your data object, or as an attribute on the parameter in the web api method, or via registration at startup.

First I’ll show the parameter binder base class.

public class PrimitiveBinder<T> : HttpParameterBinding where T : struct
{
    public PrimitiveBinder(HttpParameterDescriptor descriptor)
        : base(descriptor)
    {
    }

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        var value = actionContext.RequestContext.RouteData.Values[Descriptor.ParameterName];

        var @struct = TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(value.ToString());

        actionContext.ActionArguments[Descriptor.ParameterName] = @struct.ExplicitCastTo(Descriptor.ParameterType);

        var tsc = new TaskCompletionSource<object>();
        tsc.SetResult(null);
        return tsc.Task;
    }
}

You can see that it converts the string representation into the raw value type (which is T), then it casts the raw value type into the type of the parameter

Each strong type wrapper will have its own implementation of the binder where it passes in the underlying value type of T. As an example, here is int:

public class IntBinder : PrimitiveBinder<int>
{
    public IntBinder(HttpParameterDescriptor descriptor)
        : base(descriptor)
    {
    }
}

When the application boots up it calls the registration on the http config

public static void RegisterStrongTypes(HttpConfiguration config)
{
    config.ParameterBindingRules.Add(FindDescriptor);
}

private static HttpParameterBinding FindDescriptor(HttpParameterDescriptor descriptor)
{
    if (typeof(IGuid).IsAssignableFrom(descriptor.ParameterType))
    {
        return new GuidBinder(descriptor);
    }

    if (typeof(IInt32).IsAssignableFrom(descriptor.ParameterType))
    {
        return new IntBinder(descriptor);
    }

    if (typeof(IFloat).IsAssignableFrom(descriptor.ParameterType))
    {
        return new FloatBinder(descriptor);
    }

    return null;
}        

Now web api knows what to do based on the tagged interface of the strong type (in the int example, they are all of IInt32 interfaces).

As an example, if this is our method on the controller

[Route("int/{test}"), HttpGet]
public IntExample Test(IntExample test)
{
    return test;
}

We can pass in an int

localhost/api/int/1

And get the same value echoed back out to us without having to add any annotations to either the controller, the method, or the parameters.

Dapper

For the project I work on, we also use dapper as our micro ORM. This is great since it lets us pass in anonymous objects representing stored procedure parameters and it can auto map into objects and primitives for us. However, dapper has no idea what to do with our strong types so we have to augment its type serializer.

This is where the visitor interface comes into play. On application load, we can leverage a registration function that tells dapper what to do for the specific types. The one thorn here is that dapper can’t map an interface type to a type handler, it needs to be for each type explicity. Thats OK since we can reflectively find all types that implement the root IStrongType interface and register them automatically

internal class StrongTypeMapper : SqlMapper.ITypeHandler
{
    public void SetValue(IDbDataParameter parameter, object value)
    {
        parameter.DbType = new DbTypeStrongVisitor().Visit(value as IAcceptStrongTypeVisitor);

        parameter.Value = new UnderlyingStrongTypeVisitor().Visit(value as IAcceptStrongTypeVisitor);
    }
    
    public object Parse(Type destinationType, object value)
    {
        return value.ExplicitCastTo(destinationType);
    }
}

internal class DbTypeStrongVisitor : IStrongTypeVistor<DbType>
{
       
    public DbType Visit(IGuid guid)
    {
        return DbType.Guid;
    }

    public DbType Visit(IInt32 data)
    {
        return DbType.Int32;
    }

    public DbType Visit(IInt64 data)
    {
        return DbType.Int64;
    }

    public DbType Visit(IFloat data)
    {
        return DbType.Double;
    }

    public DbType Visit(IDouble data)
    {
        return DbType.Decimal;
    }

    public DbType Visit(IAcceptStrongTypeVisitor visitor)
    {
        return visitor.Accept(this);
    }        
}

And the initializer call:

public static void InitTypeMappings()
{
    Assembly.GetExecutingAssembly()
            .FindStrongTypes()
            .ForEach(i => SqlMapper.AddTypeHandler(i, new StrongTypeMapper()));
}

Where FindStrongTypes finds all the types that implement the generic interface of IStrongType.

But the boilerplate!

This is great and all, but kind of annoying to manage by hand. It’s a lot of boilerplate to write for what used to just be an int or float or guid. To combat this, my team is using a custom code generator that auto generates strong types along with the visitor information, and a bunch of other auto-gend data for our codebase. It’d be easy to write your own, since the template is pretty much exactly the same.

6 comments

    • Anton Kropp

      No github repo yet unfortunately, but I’ll work on extracting this out and publishing it along with a sample command line tool to auto gen strong types. In the meantime all the core pieces are in the blog post.

  1. Eamon Nerbonne

    Neat! Are you going to release something like this to github? I’ve been wrestling with similar problems, and I’m really curious where this is going :-). It’s possible roslyn will mean you don’t need the command line auto-gen by the way – nuget packages will be able to tie into the compiler.

    From my own experience doing this kind of stuff, I’ve got a tip – hopefully a useful one to you, but that depends on your usage:

    The continual use of reflection means this code will likely be slow – if you e.g. use this in Dapper and have large selects, that’s going to be the bottleneck. Fortunately, that’s entirely preventable – if you make your StrongTypeMapper generic, then Parse can use a static readonly delegate that’s constructed with the op_Explicit method – reflection will be limited to the static constructor; and runtime overhead will be a single delegate call.

    This still is far from optimal, because for no particularly good reason Dapper’s ITypeHandler deals with objects which means you’re going to be making lots of allocations, but it’s likely to make a significant difference nevertheless – a reflection call is much more expensive than an allocation.

    SetValue could be similarly optimized, but that’s not likely to matter as much since database calls tend to have few parameters but many results.

    If you don’t have any large selects, this won’t matter (i.e. reporting stuff), but if you do – I’ve noticed that the bottleneck in large but straightforward selects seems to be client-side (i.e. .NET side) data deserialization, specifically this kind of thing, so there’s a good chance this is on your hot path.

    • Anton Kropp

      Great recommendations! Internally we have some utiltieis to convert reflective parameter getting/setting into delegates so we can wrap it with that.

      We talked about hooking into rosyln plugin to auto gen the stuff resharper style, but never got around to doing it

      As for github, I’ll try and put together a demo at least of what we’re using internally, without exposing our internals :)

Post a comment

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>