tags:

views:

31

answers:

1

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 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));
 }
A: 

Have you thought about mapping to interfaces instead? Have the data contract implement an interface, and then just map to that. You could then explicitly implement the interface, effectively hiding those members.

Jimmy Bogard
Yes, that seems to work but means I'll need interfaces to match the dozens of data contracts, and then editing the autogenerated datacontracts to inherit the Interface. Too bad SVCUtil can't create the Interfaces with the client proxies. Writing the Interfaces myself is more work than just writing custom mappers. :(
Pat P
I think I can just incorporate this patch back into the fold. There's no technical reason I can't map back to all properties whether they're internal or not.
Jimmy Bogard
Its kinda hackish since it eliminates the opportunity to use fields instead of properties. I don't need fields, but some might. Maybe it would better to have an option to inject a custom property/method/field/etc finder in the configuration process much like the way custom formatters work. Anyway, keep up the good work.
Pat P

related questions