I'm on a "Combine These Two NuGet Packages in Web API" kick lately, so let's keep that going! We're going to set up an ASP.NET Web API project that uses AutoMapper and StructureMap to provide us with mapping and injection-based repositories and controllers. I already covered how to get started with StructureMap in Setting Up Dependency Injection in ASP.NET Web API, so this post will focus more on what AutoMapper does and how to use it in Dependency Injection (DI) scenarios. Let's get started!

What is AutoMapper?

AutoMapper is a convention-based mapping library that maps values from one instance of an object to another. In most cases, the values will be mapped if the name and type of the properties match in both the source and destination objects. AutoMapper is also very flexible, allowing for you to design an entirely custom mapping rule set to support any scenario. In this post, we'll mostly use AutoMapper's default settings. For more information about one of my favorite NuGet packages ever, read the docs.

Models

First off, we need the models that will be mapped. In this post, I'm assuming that one of the models represents the database structure of the object, and another model represents the Data Transfer Object variation. Here's our models:

public class DbUser
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int AccessLevelID { get; set; }
    public string Username { get; set; }
}

public class User
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public AccessLevel AccessLevel { get; set; }
    public string Username { get; set; }
}

public enum AccessLevel
{
    User,
    Admin,
    Configuration,
    Test
}

Our Repositories will need to map objects of type DbUser to objects of type User. Let's see how that would look.

Repositories

Let's make an IUserRepository interface that we can then use via dependency injection:

public interface IUserRepository
{
    List<User> GetAll();
}

We now need to implement that interface, but the Repository will need to be able to map the two user objects. In order for that to happen, we need to be able to inject the IMapper interface into the repository, Here's our UserRepository class:

public class UserRepository : IUserRepository
{
    private IMapper _mapper;

    public UserRepository(IMapper mapper)
    {
        _mapper = mapper;
    }

    public List<User> GetAll()
    {
        List<DbUser> dbUsers = new List<DbUser>()
        {
            new DbUser()
            {
                ID = 1,
                Username = "Anorak",
                FirstName = "James",
                LastName = "Halliday",
                AccessLevelID = 2
            },
            new DbUser()
            {
                ID = 2,
                Username = "Great and Powerful Og",
                FirstName = "Ogden",
                LastName = "Morrow",
                AccessLevelID = 2
            },
            new DbUser()
            {
                ID = 1020994,
                Username = "Parzival",
                FirstName = "Wade",
                LastName = "Watts",
                AccessLevelID = 1
            }
        };

        return _mapper.Map<List<User>>(dbUsers);
    }
}

But wait, don't we need to create a map for AutoMapper so that it knows how to map these objects? We do, but first, we need to set up StructureMap and add some plumbing.

Setting Up StructureMap

In order to set up StructureMap for use in a WebAPI application, I'm using the StructureMap.WebApi2 NuGet package. Said package adds several files to my project:

Screenshot of my sample project, showing the new DependencyResolution folder and new StructuremapMvc and StructuremapWebApi files.

It turns out that I don't need all of these files to implement my solution. So let's remove StructuremapMvc.cs, StructuremapWebApi.cs and StructureMapScopeModule.cs. The resulting file structure looks like this:

Screenshot of my sample project, with the above files removed.

Now we need to do some plumbing to get this structure working. In the App_Start/WebApiConfig.cs file, we need to modify the Register method like so:

public static void Register(HttpConfiguration config)
{
    // Web API configuration and services

    // Web API routes
    config.MapHttpAttributeRoutes();

    IContainer container = IoC.Initialize();
    GlobalConfiguration.Configuration.DependencyResolver = new StructureMapWebApiDependencyResolver(container);
}

In this method, we create a Dependency Injection container (IContainer) and add it to the global configuration so that it can be used. But where do we tell the container what interfaces and classes to use? In the DefaultRegistry.cs file.

In StructureMap, a Registry is a class that initializes what classes can be injected via the Container. The DefaultRegistry initially looks like this:

public class DefaultRegistry : Registry {
    #region Constructors and Destructors

    public DefaultRegistry() {
        Scan(
            scan => {
                scan.TheCallingAssembly();
                scan.WithDefaultConventions();
            });
        //For<IExample>().Use<Example>();
    }

    #endregion
}

However, I don't want that Scan() method. What it's supposed to do is automatically find injectable classes and add them to the Container, but I haven't found that it works all that well. Instead, I'll remove it for now, and we'll come back to it after we have set up AutoMapper.

Setting Up AutoMapper

Now let's go get the AutoMapper package. That package doesn't add any new files, so we need to add them ourselves.

AutoMapper works by defining "maps" that map properties from one object type to another. It does this by inspecting each type and assuming that properties which match their type and name will be mapped from one type to the other. Problem is, it doesn't create any of these maps automatically; we have to create them via the use of Profiles.

Let's create a Profile class for AutoMapper and initialize a map that maps DbUser to User:

public class UserProfile : Profile
{
    protected override void Configure()
    {
        CreateMap<DbUser, User>().ForMember(dest => dest.AccessLevel, opt => opt.MapFrom(src => (AccessLevel)src.AccessLevelID));
    }
}

Note that we had to explicitly define what property DbUser.AccessLevelID mapped to. This is because the properties do not match type, so in this case the map is a simple conversion to an enum.

Once we've got the profile defined, we need StructureMap to include it in the DI container. We can do this many ways, but the way I've found to be the most helpful involves editing the DefaultRegistry.cs file from earlier like so:

public class DefaultRegistry : Registry {
    public DefaultRegistry() {
        //Get all Profiles
        var profiles = from t in typeof(DefaultRegistry).Assembly.GetTypes()
                        where typeof(Profile).IsAssignableFrom(t)
                        select (Profile)Activator.CreateInstance(t);

        //For each Profile, include that profile in the MapperConfiguration
        var config = new MapperConfiguration(cfg =>
        {
            foreach (var profile in profiles)
            {
                cfg.AddProfile(profile);
            }
        });

        //Create a mapper that will be used by the DI container
        var mapper = config.CreateMapper();

        //Register the DI interfaces with their implementation
        For<IMapperConfiguration>().Use(config);
        For<IMapper>().Use(mapper);
    }
}

We still have an issue we need to solve, though. Remember the UserRepository from earlier? That class expects to receive an IMapper through its constructor. We need to tell the DI container that any time a class requires an object of type IUserRepository, we need to give them a class of type UserRepository. In the DefaultRegistry, we can do that like this:

public class DefaultRegistry : Registry {
    public DefaultRegistry() {
        ...
        //Register the DI interfaces with their implementation
        For<IMapperConfiguration>().Use(config);
        For<IMapper>().Use(mapper);

        //Register the UserRepository and pass instance of Mapper to its constructor
        For<IUserRepository>().Use<UserRepository>()
            .Ctor<IMapper>().Is(mapper);
    }
}

Phew! That's a lot of plumbing we needed to do! But it'll all be worth it, since creating a controller is now stupid easy.

Creating a DI-Enabled Controller

Let's create a UserController class that will serve requests. We need to pass an instance of UserRepository in the controller's constructor, and we need an action that returns all users.

[RoutePrefix("users")]
public class UserController : ApiController
{
    private IUserRepository _userRepo;

    public UserController(IUserRepository userRepo)
    {
        _userRepo = userRepo;
    }

    [Route("all")]
    [HttpGet]
    public IHttpActionResult GetAll()
    {
        return Ok(_userRepo.GetAll());
    }
}

Earlier, we needed to explicitly include the repositories into the DI container. We do not do the same for the controllers, since we already implicitly took care of that in the plumbing. All that's left to do now is test the controller.

Testing the Controller

Let's test the controller using Postman. The URL we need to hit is localhost:/users/all. What's our response?

A screenshot of a Postman response, showing status code 200 OK and the correct data returned

Which is exactly what we expected. The system is now fully DI-enabled, and AutoMapper is correctly producing the maps and delivering them to the repositories, where the actual mapping occurs.

Summary

This structure allows us to use AutoMapper and StructureMap in concert, creating extendable, testable, reusable projects at the expense of a lot of plumbing work up front. The steps we followed to enable AutoMapper and StructureMap were:

  1. Create the Models
  2. Create the Repositories
  3. Add StructureMap.WebApi2 NuGet package.
  4. Remove unnecessary StructureMap files.
  5. Add the DI Container to the WebAPI configuration.
  6. Register the Repositories with StructureMap.
  7. Add AutoMapper and Profiles.
  8. Inject IMapper into Repositories.

If you liked this post, check out the sample project, and let me know in the comments!

Happy Coding!