sebnilsson.com | Liquid Development Is What I Do
Seb Nilsson

Registering Autofac & AutoMapper Circularly

Have you ever wanted to register Autofac and AutoMapper circularly? By this I mean to do the inception of these two things, at the same time, in the same application:

  • Register AutoMapper's mappings through Autofac's component-registration for dependency-injection
  • Use registered components in Autofac for dependency-injection into AutoMapper's mapped objects

This is actually possible! It's done by providing AutoMapper with Autofac's IComponentContext-object, which is not dependent on if you've registered everything you need in the Autofac component-registrations, before configuring AutoMapper. So you can register more components after registering your AutoMapper-configuration and still access all these in your AutoMapper context when they get resolved later in your code.

We'll start with the code for registering the Autofac-components and follow it with some explaining:

public IContainer RegisterComponents()
{
    var builder = new ContainerBuilder();

    builder.RegisterType<PreMapperComponent>().As<IPreMapperComponent>();

    builder.Register(ConfigureMapper).SingleInstance();

    builder.RegisterType<PostMapperComponent>().As<IPostMapperComponent>();

    return builder.Build();
}

private IMapper ConfigureMapper(IComponentContext context)
{
    var configuration = new MapperConfiguration(config =>
    {
        var ctx = context.Resolve<IComponentContext>();

        config.CreateMap<EntityType, DtoType>()
            .ConstructUsing(_ =>
                new DtoType(ctx.Resolve<IPreMapperComponent>(), ctx.Resolve<IPostMapperComponent>()));
    });

    return configuration.CreateMapper();
}

The method RegisterComponents is included to show a somewhat realistic scenario, and for this case specifically showing that you can register components in Autofac both before and after configuring AutoMapper.

The code var ctx = context.Resolve<IComponentContext>() might look strange, but is crucial for this solution to work. Why not use the context-argument directly in the ConfigureMapper-method? Because it will throw an exception starting with This resolve operation has already ended, and instructs you to resolve IComponentContext again, which is what we're doing here.

Running the AutoMapper-code

Then we run the code using AutoMapper and the mapping of types needing dependency-injection of constructor-parameters:

public static void Run(IContainer container)
{
    var mapper = container.Resolve<IMapper>();

    var source = new EntityType(123, "Test-text", "Test-description");

    var dto = mapper.Map<DtoType>(source);

    dto.RunComponents();
}

The code dto.RunComponents() is the one that executes the injected implementations of the interfaces IPreMapperComponent and IPostMapperComponent used in the type DtoType.

You can find all the code-files involved in this example in this Gist.

This can all also be done through the recommended approach of Modules in Autofac and Profiles in AutoMapper.

C# Clamp: Limit IComparable Between Two Values

If you've ever needed to limit a value between two known limits of values, then you have been looking for Clamping.

Sometimes when you do calculations on values you know that the result should not fall outside two specific values. For example, if your calculating a percentage-value as an int-value, then you know the result should be between 0 and 100.

public int GetPercentage(int val1, int val2)
{
    // TODO: Check for 0 on val2-parameter

    var calculation = val1 / val2;
    var ensuredPercentage = calculation.Clamp(0, 100);
    return ensuredPercentage;
}

This functionality can easily be extended to all classes which inherits from System.IComparable<T>, which are for example all types of numbers like int, double, long and so on, but also DateTime and more.

The following extension-method adds the Clamp-method to all objects of types inheriting from IComparable<T>:

public static T Clamp<T>(this T value, T min, T max)
    where T : IComparable<T>
{
    var comparer = Comparer<T>.Default;

    if (comparer == null)
        throw new ArgumentException($"Failed to get default comparer for type '{typeof(T).FullName}'.");

    var isMinGreaterThanMax = comparer.Compare(min, max) > 0;

    if (isMinGreaterThanMax)
    {
        throw new ArgumentOutOfRangeException(
            nameof(min),
            "Minimum value cannot be larger than maximum value.");
    }

    var isValueLessThanMin = comparer.Compare(value, min) < 0;
    var isValueGreaterThanMax = !isValueLessThanMin && comparer.Compare(value, max) > 0;

    return isValueLessThanMin ? min : (isValueGreaterThanMax ? max : value);
}

Display Local DateTime with Moment.js in ASP.NET

Moment.js

Displaying a DateTime in local format in C# is relatively easy, but it will only use the server's settings to tell what "local" is.

For example, you might want 2016-03-07 14:35 UTC to show as 2016-03-07 15:35 for a visitor from a CET-timezone.

If you want to dynamically show the local date and time you can use the web-client's information through JavaScript and format it with Moment.js, for any user, anywhere in the world.

To do this in a way that is fault-tolerant and also SEO-friendly I want the UTC-DateTime to be hard-coded in the HTML and let Moment.js format it on the fly, when the page loads. To do this I need to populate my .cshtml-file with the following:

<span class="local-datetime"
        title="@(Model.DateUtc.ToString("yyyy-MM-dd HH:mm")) UTC"
        data-utc="@(Model.DateUtc.GetEpochTicks())">
    @(Model.DateUtc.ToString("yyyy-MM-dd HH:mm")) UTC
</span>

Make sure you run .ToUniversalTime() on your DateTime first.

Notice the .GetEpochTicks()-extension method. It makes sure the format of the DateTime is passed in a format that Moment.js can handle easily. The implementation looks like this:

private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

public static double GetEpochTicks(this DateTime dateTime)
{
    return dateTime.Subtract(Epoch).TotalMilliseconds;
}

The last step is to tell Moment.js to format our DateTime to a local format:

$('.local-datetime').each(function() {
    var $this = $(this), utcDate = parseInt($this.attr('data-utc'), 10) || 0;

    if (!utcDate) {
        return;
    }

    var local = moment.utc(utcDate).local();
    var formattedDate = local.format('YYYY-MM-DD HH:mm');
    $this.text(formattedDate);
});

If this (or other, unrelated) JavaScript-code would fail for any reason the UTC-DateTime is the actually HTML-content and will still be displayed.

NullableGuidConstraint for ASP.NET MVC & WebApi

Have you ever written a very usable Route-constraint in ASP.NET MVC or in WebAPI than you wanted to share between them both? For example a constraint that supports nullable Guids (Guid?) as route-parameter.

This can be done by implementing both System.Web.Routing.IRouteConstraint and System.Web.Http.Routing.IHttpRouteConstraint.

Hopefully this article will be obsolete with the release of ASP.NET 5, but until then, here's how you solve this problem:

public class NullableGuidConstraint : IRouteConstraint, IHttpRouteConstraint
{
    // ASP.NET MVC-signature
    public bool Match(
        HttpContextBase httpContext,
        Route route,
        string parameterName,
        RouteValueDictionary values,
        RouteDirection routeDirection)
    {
        return MatchInternal(parameterName, values);
    }

    // WebAPI-signature
    public bool Match(
        HttpRequestMessage request,
        IHttpRoute route,
        string parameterName,
        IDictionary values,
        HttpRouteDirection routeDirection)
    {
        return MatchInternal(parameterName, values);
    }

    private static bool MatchInternal(string parameterName, IDictionary values)
    {
        object value;
        if (!values.TryGetValue(parameterName, out value))
        {
            return false;
        }

        if (value is Guid)
        {
            return true;
        }

        string stringValue = Convert.ToString(value, CultureInfo.InvariantCulture);

        Guid guid;
        bool isMatch = string.IsNullOrWhiteSpace(stringValue) || Guid.TryParse(stringValue, out guid);
        return isMatch;
    }
}

Then you register this constraint through, for example, DefaultInlineConstraintResolver in System.Web.Mvc.Routing for ASP.NET MVC and System.Web.Http.Routing for WebAPI.

var constraintResolver = new DefaultInlineConstraintResolver();
constraintResolver.ConstraintMap.Add("guid?", typeof(NullableGuidConstraint));

// ASP.NET MVC
routes.MapMvcAttributeRoutes(constraintResolver);

// WebAPI
routes.MapHttpAttributeRoutes(constraintResolver);

Now you can write attribute-routes like this:

[Route("{controller}/{action}/{id=guid?}")]

Serialize HtmlString & MvcHtmlString in JSON.NET

JSON

The HtmlString-class (and MvcHtmlString) that is and has been used in the ASP.NET-platform, including WebPages, since the introduction of ASP.NET MVC is basically just a wrapped string, that doesn't gets automatically HTML-encoded when used in Razor-views. Despite this fact, if you want to serialize or deserialize this object in JSON.NET it will come back as null.

To be able to serialize an object containing a property of a type inheriting from IHtmlString, like HtmlString and MvcHtmlString, to then, for instance, cache the serialized object, you need to implement your own Newtonsoft.Json.JsonConverter that handles the serialization and deserialization.

HtmlStringConverter : Newtonsoft.Json.JsonConverter

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

public override object ReadJson(
    JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    var value = reader.Value as string;
    // Specifically MvcHtmlString
    if (objectType == typeof(MvcHtmlString))
    {
        return new MvcHtmlString(value);
    }
    // Generally HtmlString
    if (objectType == typeof(HtmlString))
    {
        return new HtmlString(value);
    }

    // Fallback for other (future?) implementations of IHtmlString
    return Activator.CreateInstance(objectType, value);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    var htmlString = value as HtmlString;
    if (htmlString == null)
    {
        return;
    }

    writer.WriteValue(htmlString.ToString());
}

You then have to register this Converter in your JsonSerializerSettings like this:

CurrentConverter.Converters.Add(new HtmlStringConverter());