Introduktion
I DFDG tilstræbes det, at AutoMapper anvendes til mapning mellem klasser. AutoMapper anvendes i dag primært i følgende situationer:
- Mapning mellem servicetyper og domænemodel (ServiceConverter)
- Mapning mellem domænemodel og wsrm-typer (WsrmConverter)
- Mapning mellem domænemodel og eksterne serviceklasser fx ved kald til Jobnet (ExternalServiceMapper)
ServiceConverter
ServiceConvertere aka ServiceMappere anvendes til at konvertere mellem servicetyper og domæneobjekter. For nye services bør følgende principper følges:
Placering og navngivning
For alle services laves en converter klasse, der nedarver fra MapperBase. Converteren navngives efter servicen, fx vil InterviewService have en converter, der hedder InterviewServiceConverter. Det er besluttet, at vi kalder det en converter og ikke en mapper. MapperBase findes under namespacet DFDG.ServiceGateway.Utilities
Kodelister
Når en converter nedarver fra MapperBase, mappes der automatisk mellem kodeliste-enums og kodelistetyper - uanset retning og uanset om de properties, der mappes mellem er nullable eller ej. Eksempel:
Nedenfor vises et tænkt eksempel, hvor der mappes mellem typerne InterviewType og InterviewModel
public class InterviewModel
{
public InterviewTypeIdentifierEnum InterviewTypeIdentifier { get; set; }
}
[DataContract(Namespace = "http://service.bm.dk/pjaktass/1/InterviewService")]
public class InterviewType
{
[DataMember(Order = 1)]
[Required]
[Description("Samtaletype")]
public InterviewTypeIdentifierType InterviewTypeIdentifier { get; set; }
}
Modellen har en property, som er en kodeliste-enum mens servicetypen har en property, der er en kodelistetype. Da de to properties hedder det samme, skal rammeværket nok sørge for at mappe mellem de to. Dvs man ender med en mapper konfiguration, der ser således ud:
config.CreateMap<Model.InterviewModel, Service.InterviewType>()
I tilfælde af at de to properties ikke er navngivet ens, ser konfigurationen således ud:
config.CreateMap<Model.InterviewModel, Service.InterviewType>()
.ForMemberMapFrom(dest => dest.InterviewTypeIdentifierType, src => src.InterviewTypeIdentifierEnum)
Konventioner
Undgå explicitte mappings
Undgå at mappe mellem properties med samme navn. AutoMapper gør det for dig. AutoMapper kan selv finde ud af, det, hvis casing er forskellig og propertytyperne for forskellige. Eksempel på, hvad man IKKE skal gøre:
config.CreateMap<Model.InterviewModel, Service.InterviewType>()
.ForMemberMapFrom(dest => dest.Identifier, src => src.Id)
Anvend extentionmetoder
For at gøre livet lettere for udviklerne er er udviklet extensionmetoder til de mest gængse mapping-relaterede operationer:
// Uden extensionmetode
.ForMember(dest => dest.Identifier, opt => opt.MapFrom(src => src.Id))
// Med extensionmetode
.ForMemberMapFrom(dest => dest.Identifier, src => src.Id)
IgnoreMember
// Uden extensionmetode
.ForMember(dest => dest.Identifier, opt => opt.Ignore())
// Med extensionmetode
.IgnoreMember(dest => dest.Identifier)
// Uden extensionmetode
.ForMember(dest => dest.Identifier, opt => opt.UseValue(42))
// Med extensionmetode
.ForMemberUseValue(dest => dest.Identifier, 42)
Test
Der findes en unittest, der automatisk kalder AssertConfigurationIsValid på alle convertere, der nedarver fra MapperBase. Dermed er der ikke behov for at skrive selvstændige tests til de enkelte convertere.
I nogle situationer kan det være en fordel at lave en unittest, hvor converterens metoder kaldes med dummy data. Dermed sandsynliggøres det yderligere, at converteren fungerer efter hensigten. Et eksempel på en sådan test ses her:
[TestMethod]
[TestCategory("UnitTest"), TestCategory("MyPlan")]
public void MyPlanPdfContainerMapper_ConversionSuccessful()
{
var mapper = new MyPlanPdfContainerMapper();
MyPlanModel myPlan = _fixture.Create<MyPlanModel>();
List<ActivityItemModel> activityItems = _fixture.Build<ActivityItemModel>().CreateMany().ToList();
KC.AMS.Model.ServiceModel.PersonNameStructureType personName = _fixture.Create<KC.AMS.Model.ServiceModel.PersonNameStructureType>();
var container = new MyPlanContainer(myPlan, activityItems, personName);
var pdfContainer = new MyPlanPdfContainer(container, _fixture.Create<bool>(), _fixture.Create<bool>());
var result = mapper.Convert(pdfContainer, _fixture.Create<bool>());
Assert.IsNotNull(result); // We don't check that all properties are converted correctly (because there are many), but just that the converter doesn't throw an exception
}
WsrmConverter
For wsrmconvertere gælder stort set samme regelsæt som for serviceconvertere med den forskel, at der laves én converter per wsrm-besked.
ExternalServiceConverter
For converters brugt til konvertering mellem domænemodel og proxyklasser til en ekstern service, gælder samme regelsæt som for serviceconvertere