Как я могу использовать AutoMapper для свойств, помеченных как Внутренние? - PullRequest
2 голосов
/ 09 июля 2010

У меня есть решение с несколькими проектами.Проект бизнес-компонентов, веб-приложение MVC, проект DTO и ViewModels, проект модульного тестирования бизнес-компонента и проект модульного тестирования MVC.В общем, не слишком необычно.Бизнес-компонент имел ссылку Service на несколько конечных точек WCF.Внутри бизнес-компонента контракты данных из конечных точек WCF автоматически преобразуются с помощью AutoMapper в данные, необходимые для моделей представления.Проблема, которую я хотел решить, заключалась в том, что POCO контракта данных в автоматически сгенерированных прокси-серверах WCF все PUBLIC, поэтому, когда я ссылаюсь на свой бизнес-компонент из моего веб-приложения MVC (фактически внедряется через StructureMap, поэтому я могу использовать фиктивный бизнес-компонент, если мне нужно), У меня есть доступ к POCO WCF из веб-приложения.Поскольку над веб-приложением будут работать несколько других разработчиков, я бы предпочел, чтобы они не испытывали соблазна напрямую использовать POCO WCF, а проходили через бизнес-компоненты.Поэтому я удалил ссылку на службу в бизнес-компонентах и ​​вместо этого добавил скрипт, который вызывает SVCUTIL с флагом / INTERNAL, чтобы автоматически сгенерированные классы были помечены как ВНУТРЕННИЕ, а не публичные.Однако теперь AutoMapper не будет отображаться в / из моего POCO контракта на данные.

Я не смог найти никакой документации, которая показывала бы мне, как заставить AutoMapper работать со свойствами ВНУТРЕННЕГО, поэтому я извлек источник из github иизменил TypeInfo.cs так, чтобы он игнорировал поля и включал непубличные члены.Теперь мое решение работает отлично, но я чувствую себя довольно странно, имея собственную версию AutoMapper.Кажется, должен быть способ сопоставить POCO с контрактом данных WCF без необходимости быть ОБЩЕСТВЕННЫМ.Чего мне не хватает?

Изменено 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));
 }

Ответы [ 3 ]

7 голосов
/ 23 мая 2016

Просто установите свойство ShouldMapProperty вашего объекта конфигурации в методе initialize.

Вот пример использования статического API, однако вы должны быть в состоянии достичь того же самого с помощью нестатического API.

Mapper.Initialize(i =>
{
    i.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
    i.CreateMap<Source, Target>();                
});
1 голос
/ 03 ноября 2011

Используйте это.Он отлично работает с частными и внутренними полями.

http://ragingpenguin.com/code/privatefieldresolver.cs.txt

использование:

// in one library
public class Foo
{
internal string _bar = "some value";
}

// in another library
public class FooModel
{
public string Bar { get; set; }
}

Mapper.CreateMap<Foo, FooModel>()
.ForMember(x => x.Bar, o => o.ResolveUsing(new PrivateFieldResolver("_bar")));

Работает как шарм.

0 голосов
/ 09 июля 2010

Задумывались ли вы о сопоставлении интерфейсов? Сделайте так, чтобы контракт данных реализовал интерфейс, а затем просто сопоставьте его. Затем вы можете явно реализовать интерфейс, эффективно скрывая эти элементы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...