Skip to content

Jimmy Bogard
Syndicate content
Strong opinions, weakly held
Updated: 3 hours 12 min ago

AutoMapper 5.1 released

Wed, 08/17/2016 - 22:28

Release notes here: AutoMapper 5.1

Some big things from this release:

  • Supporting portable class libraries (again), profile 111. Because converting projects from PCL to netstandard is hard
  • More performance improvements (mainly in complex mappings), 70% faster in our benchmarks
  • Easy initialization via assembly scanning

As part of the release, we closed 57 issues. With the new underlying mapping engine, there were a few bugs to work out, which this release worked to close.

Enjoy!

Categories: Blogs

Integrating AutoMapper with ASP.NET Core DI

Wed, 07/20/2016 - 18:30

Part of the release of ASP.NET Core is a new DI framework that’s completely integrated with the ASP.NET pipeline. Previous ASP.NET frameworks either had no DI or used service location in various formats to resolve dependencies. One of the nice things about a completely integrated container (not just a means to resolve dependencies, but to register them as well), means it’s much easier to develop plugins for the framework that bridge your OSS project and the ASP.NET Core app. I already did this with MediatR and HtmlTags, but wanted to walk through how I did this with AutoMapper.

Before I got started, I wanted to understand what the pain points of integrating AutoMapper with an application are. The biggest one seems to be the Initialize call, most systems I work with use AutoMapper Profiles to define configuration (instead of one ginormous Initialize block). If you have a lot of these, you don’t want to have a bunch of AddProfile calls in your Initialize method, you want them to be discovered. So first off, solving the Profile discovery problem.

Next is deciding between the static versus instance way of using AutoMapper. It turns out that most everyone really wants to use the static way of AutoMapper, but this can pose a problem in certain scenarios. If you’re building a resolver, you’re often building one with dependencies on things like a DbContext or ISession, an ORM/data access thingy:

public class LatestMemberResolver : IValueResolver<object, object, User> {
  privat readonly AppContext _dbContext;
  public LatestMemberResolver(AppContext dbContext) {
    _dbContext = dbContext;
  }
  
  public User Resolve(object source, object destination, User destMember, ResolutionContext context) {
    return _dbContext.Users.OrderByDescending(u => u.SignUpDate).FirstOrDefault();
  }
}

With the new DI framework, the DbContext would be a scoped dependency, meaning you’d get one of those per request. But how would AutoMapper know how to resolve the value resolver correctly?

The easiest way is to also scope an IMapper to a request, as its constructor takes a function to build value resolvers, type converters, and member value resolvers:

IMapper mapper 
  = new Mapper(Mapper.Configuration, t => ServiceLocator.Resolve(t));

The caveat is you have to use an IMapper instance, not the Mapper static method. There’s a way to pass in the constructor function to a Mapper.Map call, but you have to pass it in *every single time*, and thus not so useful:

Mapper.Map<User, UserModel>(user, 
  opt => opt.ConstructServicesUsing(t => ServiceLocator.Resolve(t)));

Finally, if you’re using AutoMapper projections, you’d like to stick with the static initialization. Since the projection piece is an extension method, there’s no way to resolve dependencies other than passing them in, or service location. With static initialization, I know exactly where to go to look for AutoMapper configuration. Instance-based, you have to pass in your configuration to every single ProjectTo call.

In short, I want static initialization for configuration, but instance-based usage of mapping. Call Mapper.Initialize, but create mapper instances from the static configuration.

Initializating the container and AutoMapper

Before I worry about configuring the container (the IServiceCollection object), I need to initialize AutoMapper. I’ll assume that you’re using Profiles, and I’ll simply scan through a list of assemblies for anything that is a Profile:

private static void AddAutoMapperClasses(IServiceCollection services, IEnumerable<Assembly> assembliesToScan)
{
    assembliesToScan = assembliesToScan as Assembly[] ?? assembliesToScan.ToArray();

    var allTypes = assembliesToScan.SelectMany(a => a.ExportedTypes).ToArray();

    var profiles =
    allTypes
        .Where(t => typeof(Profile).GetTypeInfo().IsAssignableFrom(t.GetTypeInfo()))
        .Where(t => !t.GetTypeInfo().IsAbstract);

    Mapper.Initialize(cfg =>
    {
        foreach (var profile in profiles)
        {
            cfg.AddProfile(profile);
        }
    });

The assembly list can come from a list of assemblies or types passed in to mark assemblies, or I can just look at what assemblies are loaded in the current DependencyContext (the thing ASP.NET Core populates with discovered assemblies):

public static void AddAutoMapper(this IServiceCollection services)
{
    services.AddAutoMapper(DependencyContext.Default);
}

public static void AddAutoMapper(this IServiceCollection services, DependencyContext dependencyContext)
{
    services.AddAutoMapper(dependencyContext.RuntimeLibraries
        .SelectMany(lib => lib.GetDefaultAssemblyNames(dependencyContext).Select(Assembly.Load)));
}

Next, I need to add all value resolvers, type converters, and member value resolvers to the container. Not every value resolver etc. might need to be initialized by the container, and if you don’t pass in a constructor function it won’t use a container, but this is just a safeguard just in case something needs to resolve these AutoMapper service classes:

var openTypes = new[]
{
    typeof(IValueResolver<,,>),
    typeof(IMemberValueResolver<,,,>),
    typeof(ITypeConverter<,>)
};
foreach (var openType in openTypes)
{
    foreach (var type in allTypes
        .Where(t => t.GetTypeInfo().IsClass)
        .Where(t => !t.GetTypeInfo().IsAbstract)
        .Where(t => t.ImplementsGenericInterface(openType)))
    {
        services.AddTransient(type);
    }
}

I loop through every class and see if it implements the open generic interfaces I’m interested in, and if so, registers them as transient in the container. The “ImplementsGenericInterface” doesn’t exist in the BCL, but it probably should :) .

Finally, I register the mapper configuration and mapper instances in the container:

services.AddSingleton(Mapper.Configuration);
services.AddScoped<IMapper>(sp => 
  new Mapper(sp.GetRequiredService<IConfigurationProvider>(), sp.GetService));

While the configuration is static, every IMapper instance is scoped to a request, passing in the constructor function from the service provider. This means that AutoMapper will get the correct scoped instances to build its value resolvers, type converters etc.

With that in place, it’s now trivial to add AutoMapper to an ASP.NET Core application. After I create my Profiles that contain my AutoMapper configuration, I instruct the container to add AutoMapper (now released as a NuGet package from the AutoMapper.Extensions.Microsoft.DependencyInjection package):

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    services.AddAutoMapper();

And as long as I make sure and add this after the MVC services are registered, it correctly loads up all the found assemblies and initializes AutoMapper. If not, I can always instruct the initialization to look in specific types/assemblies for Profiles. I can then use AutoMapper statically or instance-based in a controller:

public class UserController {
  private readonly IMapper _mapper;
  private readonly AppContext _dbContext;
  public UserController(IMapper mapper, AppContext dbContext) {
    _mapper = mapper;
    _dbContext = dbContext;
  }
  
  public IActionResult Index() {
    var users = dbContext.Users
      .ProjectTo<UserIndexModel>()
      .ToList();
      
    return View(users);
  }
  
  public IActionResult Show(int id) {
    var user = dbContext.Users.Where(u => u.Id == id).Single();
    var model = _mapper.Map<User, UserIndexModel>(user);
    
    return View(model);
  }
}

The projections use the static configuration, while the instance-based uses any potential injected services. Just about as simple as it can get!

Other containers

While the new AutoMapper extensions package is specific to ASP.NET Core DI, it’s also how I would initialize and register AutoMapper with any container. Previously, I would lean on DI containers for assembly scanning purposes, finding all Profile classes, but this had the unfortunate side effect that Profiles could themselves have dependencies – a very bad idea! With the pattern above, it should be easy to extend to any other DI container.

Categories: Blogs

MediatR Extensions for Microsoft Dependency Injection Released

Tue, 07/19/2016 - 21:07

To help those building applications using the new Microsoft DI libraries (used in Orleans, ASP.NET Core, etc.), I pushed out a helper package to register all of your MediatR handlers into the container.

MediatR.Extensions.Microsoft.DependencyInjection

To use, just add the AddMediatR method to wherever you have your service configuration at startup:

public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc();

  services.AddMediatR(typeof(Startup));
}

You can either pass in the assemblies where your handlers are, or you can pass in Type objects from assemblies where those handlers reside. The extension will add the IMediator interface to your services, all handlers, and the correct delegate factories to load up handlers. Then in your controller, you can just use an IMediator dependency:

public class HomeController : Controller
{
  private readonly IMediator _mediator;

  public HomeController(IMediator mediator)
  {
    _mediator = mediator;
  }
  public IActionResult Index()
  {
    var pong = _mediator.Send(new Ping {Value = "Ping"});
    return View(pong);
  }
}

And you’re good to go. Enjoy!

Categories: Blogs

HtmlTags 4.1 Released for ASP.NET 4 and ASP.NET Core

Mon, 07/18/2016 - 20:20

One of the libraries that I use on most projects (but probably don’t talk about it much) is now updated for the latest ASP.NET Core MVC. In order to do so, I broke out the classic ASP.NET and ASP.NET Core pieces into separate NuGet packages:

Since ASP.NET Core supports DI from the start, it’s quite a bit easier to integrate HtmlTags into your ASP.NET Core application. To enable HtmlTags, you can call AddHtmlTags in the method used to configure services in your startup (typically where you’d have the AddMvc method):

services.AddHtmlTags(reg =>
{
    reg.Labels.IfPropertyIs<bool>()
       .ModifyWith(er => er.CurrentTag.Text(er.CurrentTag.Text() + "?"));
});

The AddHtmlTags method takes a configuration callback, a params array of HtmlConventionRegistry objects, or an entire HtmlConventionLibrary. The one with the configuration callback includes some sensible defaults, meaning you can pretty much immediately use it in your views.

The HtmlTags.AspNetCore package includes extensions directly for IHtmlHelper, so you can use it in your Razor views quite easily:

@Html.Label(m => m.FirstName)
@Html.Input(m => m.FirstName)
@Html.Tag(m => m.FirstName, "Validator")

@Html.Display(m => m.Title)

Since I’m hooked in to the DI pipeline, you can make tag builders that pull in a DbContext and populate a list of radio buttons or drop down items from a table (for example). And since it’s all object-based, your tag conventions are easily testable, unlike the tag helpers which are solely string based.

Enjoy!

Categories: Blogs

AutoMapper 5.0 Released

Thu, 07/07/2016 - 17:42

Release notes:

Today I pushed out AutoMapper 5.0.1, the culmination of about 9 months of work from myself and many others to build a better, faster AutoMapper. Technically I pushed out a 5.0.0 package last week, but it turns out that almost nobody really pulls down beta packages to submit bugs so this package fixes the bugs reported from the 5.0.0 drop :)

The last 4.x release introduced an instance-based configuration model for AutoMapper, and with 5.0, we’re able to take advantage of that model to focus on speed. So how much faster? In our benchmarks, 20-50x faster. Compared to hand-rolled mappings, we’re still around 8-10x slower, mostly because we’re taking care of null references, providing diagnostics, good exception messages and more.

To get there, we’ve converted the runtime mappings to a single compiled expression, making it as blazing fast as we can. There’s still some micro-optimizations possible, which we’ll look at for the next dot release, but the gains so far have been substantial. Since compiled expressions give you zero stack trace if there’s a problem, we made sure to preserve all of the great diagnostic/error information to figure out how things went awry.

We’ve also expanded many of the configuration options, and tightened the focus. Originally, AutoMapper would do things like keep track of every single mapped object during mapping, which made mapping insanely slow. Instead, we’re putting the controls back into the developer’s hands of exactly when to use what feature, and our expression builder builds the exact mapping plan based on how you’ve configured your mappings.

This did mean some breaking changes to the API, so to help ease the transition, I’ve included a 5.0 upgrade guide in the wiki.

Enjoy!

Categories: Blogs