Is this a breaking change between AutoMapper 2.0.0 and 2.2.0?
Asked Answered
M

2

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.

Madid answered 21/11, 2012 at 20:36 Comment(3)
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.Manger
It doesn't look like you're going to get much luck here. I suggest you ask on the AutoMapper mailing list - that's where the experts hang out :)Inefficient
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.Hydrotherapy
P
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.

Probation answered 23/1, 2013 at 12:47 Comment(2)
Yes, if you read the code in the question, that is what I am doing.Madid
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.Probation
I
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[].

Inion answered 25/5, 2013 at 19:30 Comment(3)
I don't think T[] is mutable. That is what Enumerable.Empty<T> uses by default.Madid
But it can be resized/mutated, unlike the Enumerable.Empty&lt;T&gt; reference which is read-only.Inion
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.Madid

© 2022 - 2024 — McMap. All rights reserved.