Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use AutoMapper on properties marked Internal?

Tags:

c#

automapper

I have a solution with several projects. A business components project, an MVC web app, a DTO's and ViewModels project, a business component unit test project, and an MVC unit test project. All in all, not too unusual. The business component had a Service reference to several WCF endpoints. Within the business component, the data contracts from the WCF end points gets automapped using AutoMapper into the data necessary for the ViewModels. The problem I wanted to solve was that the data contract POCO's in the autogenerated WCF proxies are all PUBLIC, so when I reference my business component from my MVC web app (actually injected via StructureMap so I can use a mock business component if I need to), I have access to the WCF POCO's from within the web app. Since several other developers will be working on the web app, I'd prefer them not to be tempted to directly use the WCF POCO's but instead go through the business components. So I removed the service reference in the business components and instead added a script that invokes SVCUTIL with the /INTERNAL flag so that the autogenerated classes are marked INTERNAL instead of public. However, now AutoMapper won't map to/from my data contract POCO's.

I could not find any documentation that would show me how to get AutoMapper to work with INTERNAL properties, so I pulled the source from github and modified TypeInfo.cs so that it ignored Fields and included nonpublic members. Now my solution works perfectly, but feels pretty hackish having my own custom version of AutoMapper. It seems there should be a way to map from WCF data contract POCO's without them having to be PUBLIC. What am I missing?

Changed TypeInfo.cs

private IEnumerable<MemberInfo> GetAllPublicReadableMembers()
{
    IEnumerable<Type> typesToScan = new[] { Type, Type.BaseType };

    if (Type.IsInterface)
        typesToScan = typesToScan.Concat(Type.GetInterfaces());

    return typesToScan
        .Where(x => x != null)
        .SelectMany(x => x.FindMembers(
            MemberTypes.Property, //changed this
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, //and this
            (m, f) => m is FieldInfo ||
                      m is PropertyInfo && ((PropertyInfo)m).CanRead && !((PropertyInfo)m).GetIndexParameters().Any(),
            null)
        );
}
like image 324
Pat P Avatar asked Jul 08 '10 21:07

Pat P


People also ask

When should you not use AutoMapper?

If you have to do complex mapping behavior, it might be better to avoid using AutoMapper for that scenario. Reverse mapping can get very complicated very quickly, and unless it's very simple, you can have business logic showing up in mapping configuration.

Where is AutoMapper used?

AutoMapper is used whenever there are many data properties for objects, and we need to map them between the object of source class to the object of destination class, Along with the knowledge of data structure and algorithms, a developer is required to have excellent development skills as well.

Does AutoMapper map private fields?

By default, AutoMapper only recognizes public members. It can map to private setters, but will skip internal/private methods and properties if the entire property is private/internal.


1 Answers

Just set the ShouldMapProperty property of your configuration object in the initialize method.

Here is an example using the static API, however, you should be able to achieve the same in a similar fashion by using the non-static API.

Mapper.Initialize(i =>
{
    i.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
    i.CreateMap<Source, Target>();                
});

If you use a profile, this must go in the constructor:

public class MyProfile : Profile
{
    public MyProfile()
    {
        ShouldMapProperty = arg => arg.GetMethod.IsPublic || arg.GetMethod.IsAssembly;

        // The mappings here.
    }
}
like image 66
CShark Avatar answered Sep 28 '22 05:09

CShark