Automapper: Protobuf/gRPC RepeatedField support

Created on 19 Feb 2020  路  6Comments  路  Source: AutoMapper/AutoMapper

This was previously raised in now-closed ticket https://github.com/AutoMapper/AutoMapper/issues/3157

I am using Google.Protobuf (and gRPC, but that is not important).

Protobuf RepeatedField properties are implemented as readonly fields with getter only.

Current code generated for populating RepeatedField's doesn't work, as you need to "Add" to RepeatedField collection instead of assigning a new value to it. This is a series of tedious foreach loops in AfterMap (one for each property).

There should be a way to specify to automapper that you need to "Add" to pre-instantiated collection instead of instantiating a new one. This would not require physical dependency to Google.Protobuf

Question

Most helpful comment

Because in generated c# classes from proto all collection are RepeatedField properties with get only backing fields which always readonly and initialized on construction, found this workaround, works for me:

var config = new MapperConfiguration(
cfg =>
{
  cfg.CreateMap<Person, PersonGrpcDto>().ReverseMap();
  cfg.ForAllPropertyMaps(
    map => map.DestinationType.IsGenericType && map.DestinationType.GetGenericTypeDefinition() == typeof(RepeatedField<>),
    (map, options) => options.UseDestinationValue());
});

@vivainio So, just add UseDestinationValue() and it should work

All 6 comments

Possible api could be:

// now RepeatedField is only ever Add():ed to, never assigned
cfg.TreatCollectionAsReadOnly<RepeatedField>()

I thought we supported readonly collections. What does your destination type look like? Gist?

Destination type is the one generated from proto files: https://gist.github.com/vivainio/e1129348d38f061856b28b35d4fd830d

You can build it yourself by doing "dotnet new grpc", then editing greet.proto to convert property to repeated:

message HelloRequest {
  repeated string name = 1;
}

After dotnet build, the generated file will be in obj\Debug\netcoreapp3.1\Greet.cs

I think this is better suited for StackOverflow.

Because in generated c# classes from proto all collection are RepeatedField properties with get only backing fields which always readonly and initialized on construction, found this workaround, works for me:

var config = new MapperConfiguration(
cfg =>
{
  cfg.CreateMap<Person, PersonGrpcDto>().ReverseMap();
  cfg.ForAllPropertyMaps(
    map => map.DestinationType.IsGenericType && map.DestinationType.GetGenericTypeDefinition() == typeof(RepeatedField<>),
    (map, options) => options.UseDestinationValue());
});

@vivainio So, just add UseDestinationValue() and it should work

Was this page helpful?
0 / 5 - 0 ratings