32

I updated from AutoMapper 2.0.0 to 2.2.0 today and realized the update broke some code. Wanted to ask about it here before posting as an issue on the automapper github site.

One of my destination types initializes a collection property like so:

public class PageOf<TModel>
{
    public PageOf()
    {
        Items = Enumerable.Empty<TModel>();
    }

    public IEnumerable<TModel> Items { get; set; }
}

With automapper 2.0.0, this was fine. When I updated to 2.2.0, mapping to this destination type caused a NotSupportedException with the message "Collection was of a fixed size." (That exception was wrapped inside an AutoMapperMappingException.)

I was able to fix the issue by changing the constructor code above to this:

public PageOf()
{
    Items = new List<TModel>();
}

It seems as if AutoMapper 2.0.0 was discarding whatever value was in the Items property and using the set Property accessor, whereas AutoMapper 2.2.0 is just using the get property accessor and trying to modify the existing IEnumerable. It looks like Enumerable.Empty<TModel>() is just substituting a zero-length array, which would explain the exception.

Is this a bug? What in AutoMapper changed between 2.0.0 and 2.2.0 that would cause it to ignore the destination property setter and instead try to modify the existing collection?

Update:

As requested, here is the CreateMap call:

public class PagedQueryResultToPageOfItemsProfiler : Profile
{
    protected override void Configure()
    {
        CreateMap<PagedQueryResult<EstablishmentView>, PageOfEstablishmentApiModel>();
    }
}

The PageOfEstablishmentApiModel class inherits from PageOf<EstablishmentApiModel>.

Here is the Mapper.Map code:

var query = Mapper.Map<EstablishmentViewsByKeyword>(input);
var results = _queryProcessor.Execute(query);
var model = Mapper.Map<PageOfEstablishmentApiModel>(results); // exception here

If a special mapping configuration is necessary (for example .ConvertUsing(x => x)) in AutoMapper going from 2.0.0 to 2.2.0, we may have to hang onto the old version. I always liked how AM automatically converted collection properties, and without that, AM seems more like ValueInjecter.

Athari
  • 33,702
  • 16
  • 105
  • 146
danludwig
  • 46,965
  • 25
  • 159
  • 237
  • Can you post your Automapper code too? ie: `Mapper.Map` method calls (are you using generic methods?). This is likely "by design" and easily reverted to your old behavior with the right mapper method or mapper configuration. You can return an array from automapper and assign it to your IEnumerable property as in the docs on github. I'll post an example or two as an answer once I see your code that performs the map. – BenSwayne Nov 29 '12 at 17:39
  • 2
    It doesn't look like you're going to get much luck here. I suggest you ask on the [AutoMapper mailing list](https://groups.google.com/forum/?fromgroups#!forum/automapper-users) - that's where the experts hang out :) – Mightymuke Dec 01 '12 at 10:00
  • Did you previously reviewed AutoMapper 2.2.0 support for keep backward compatiblity? There are cases where features/functionalities are discontinued ( not longer supported) from a product and newever versions rquires apps refactoring. – G21 Jan 11 '13 at 13:31

2 Answers2

1

Have you tried to use the Map method that way: Mapper.Map<DestinationClass, SourceClass>(object to convert)

?

With the 2.2 version of AutoMapper, this is how we use it and it works fine for us.

Nicolas Landier
  • 140
  • 1
  • 9
  • 2
    Yes, if you read the code in the question, that is what I am doing. – danludwig Jan 23 '13 at 17:52
  • Sorry, I have edited my answer because the generic types were not displayed. Wanted to ask if you were specifying the source class and the destination class when calling the Map method. – Nicolas Landier Feb 06 '13 at 21:54
0

I'm guessing that it is trying to add to your collection, but since your collection is a readonly instance (Enumerable.Empty<T>), it can't actually modify it. I'd assume you are correct that AutoMapper changed the code around how they instantiate the new type. Use a mutable instance instead such as new List<T>() or T[].

glts
  • 21,808
  • 12
  • 73
  • 94
Haney
  • 32,775
  • 8
  • 59
  • 68
  • I don't think `T[]` is mutable. That is what `Enumerable.Empty` uses by default. – danludwig May 28 '13 at 17:50
  • But it can be resized/mutated, unlike the Enumerable.Empty<T> reference which is read-only. – Haney May 28 '13 at 18:25
  • Last time I checked, arrays cannot be resized after they are created. They are fixed length. You can convert an array to a list, change its size, then convert that back to another array, but you cannot resize an array directly. – danludwig May 29 '13 at 01:16