Skip to main content

Unexpected AutoMapper behavior

· 2 min read
Pär Dahlman
Backend Engineer

With every upgrade of a major version of AutoMapper there are many things that break. Recently I've been involved in upgrading not one or two majors but from 8.x to the latest and presumably greatest 13.0.1. After removing calls to obsolete methods, removing duplicate and explicitly added mappings of child types that previously was inferred. The migration was done. The confidence was high as the unit tests that verified the mapping configuration passed:

new MapperConfiguration(cfg => cfg.AddProfile<Profile>())
.AssertConfigurationIsValid();

A few seconds after the code was deployed errors started to appear in the application log.

That's strange.

Because this was real life, the profile contained so much mapping of complex objects that is was difficult to identify what had happened. Finally, I managed to create a small repro app. Basically AssertConfigurationIsValid fails to detect that mapping of concrete types is missing if said type implements interface that is registered. Let's have a look at an example:

Source types
public interface ISourceProperty { }

public record SourceProperty : ISourceProperty;

public class SourceRoot
{
public SourceProperty Property { get; set; }
}

Here SourceRoot has a property of concrete type SourceProperty that happens to implement ISourceProperty. The destination types are copies, but obviously named differently 😉

Destination types
public interface IDestinationProperty { }

public record DestinationProperty : IDestinationProperty;

public class DestinationRoot
{
public DestinationProperty Property { get; set; }
}

With the following mapper configuration

Mapper configuration
var mapperConfiguration = new MapperConfiguration(cfg =>
{
cfg.CreateMap<SourceRoot, DestinationRoot>();
cfg.CreateMap<ISourceProperty, IDestinationProperty>();
});

The mapperConfiguration.AssertConfigurationIsValid() does not throw, even though the concrete types for the Property property is not registered. When trying to use AutoMapper to actually map between SourceRoot and DestinationRoot an exception is thrown

Unhandled exception. AutoMapper.AutoMapperMappingException: Error mapping types.

Mapping types:
SourceRoot -> DestinationRoot
SourceRoot -> DestinationRoot

Type Map configuration:
SourceRoot -> DestinationRoot
SourceRoot -> DestinationRoot

Destination Member:
Property

I raised the issue over at GitHub, but it was closed without making it clear to me if this is a bug that will be fixed or if it is by design 🤷.

Temporary workaround

Until this has been address in AutoMapper, the only way to know for certain if the mapping is correct is to try to perform mapping of the "root objects" in a unit test. This is what the application code does, after all.

Seven lines of code in the pipeline

· 4 min read
Pär Dahlman
Backend Engineer

There are a few resemblance between a CI pipeline and a kitchen sink. When it has just been installed it does its job efficiently and after a while its functionality is taken for granted. But the same way that a sink becomes clogged over time, a pipeline tend to grow slow, complex and/or bloated. An just like with the sink, the change is incremental and slow that it's hard to notice the decay. And lastly, before this comparison is put aside: they are both integral components in crucial workflows.

Cluster RabbitMQ in Docker

· 5 min read
Pär Dahlman
Backend Engineer

Docker is the kind of technology that grows on you. A couple of months I barely knew the difference between a container and image, but lately I've been exploring the benefits of using docker to spin up my local development environment and it is impressive how easy it is to getting started.

In this post, I describe how I created this Github repo, that clusters three RabbitMQ servers without building any custom images for it.

Local setup in minutes

· 6 min read
Pär Dahlman
Backend Engineer

TL;DR this is a Docker love story. Why spend hours setting up your development environment, when it can be done with a single command? Sort of, anyways.

A couple of months ago, I bought a new PC for .NET development on Windows. Little did I know that it was shipped with a damaged disk that decided to give up only weeks after I had set up my local development environment. By that time, I had installed Erlang, RabbitMQ, Elastic, Kibana, MongoDB, SQL Server and a few other applications I needed.

A truly event driven web

· 7 min read
Pär Dahlman
Backend Engineer

Ever been to one of those aggregating search sites where the result list is populated in chunks, rather than all at once? Ever wondered how it works? Event driven sites are robust, extendable - and if you're on a messaging system like RabbitMQ and a .NET client like RawRabbit, it is pretty easy to get started.

Making sense of all those logs

· 6 min read
Pär Dahlman
Backend Engineer

It is indeed a change of mindset to break up larger applications into smaller, contained services. One aspect of the transition, that is often somewhat overlooked, is the log file havoc that often sneak up on you when you least want it.

Logging is inherently difficult to make right. I believe one reason for this is that as a developer, running the application locally, there are better tools available for understanding what's going on. .NET developers has been spoiled by the first class debugging experience in Visual Studio for quite some time. My experience is that logging is often an after-thought to a period of optimistic testing.

Logging is often an after-thought to a period of optimistic testing.

The year of secure internet connections

· 4 min read
Pär Dahlman
Backend Engineer

Times are a-changin'

It was the price of SSL cert that was the tipping point for me. In general, I like paying for high quality services. Companies like Github is a perfect example; low up-front cost, easy to use interface and a bunch of useful integrations that actually increases productivity.

One method to rule them all

· 5 min read
Pär Dahlman
Backend Engineer

I wasn't thrilled when Owin was introduced back in 2012. Sure, I could see the benefits in an abstraction layer between the web server and the application, but I didn't really see the full potential of the ecosystem of middlewares that came about a few months later. Then, for a long time, my only relation to these middleware was through extension methods like

public void Configuration(IAppBuilder app)
{
app.UseFoo();
app.UseBar();
}