AutoMapper.Map overload with IMappingOperations missing from ResolutionContext.Mapper - automapper

I have a TypeConverter in which I'm using context.Mapper.Map() to map two subproperties.
The properties are the same Type and use the same (another) TypeConverter. However in one the properties I need to pass some IMappingOperationsOptions.
It looks like this (simplified):
public class MyTypeConverter : ITypeConverter<A, B>
{
public B Convert(A, B, ResolutionContext context)
{
var subProp1 = context.Mapper.Map<C>(B.SomeProp);
var subProp2 = context.Mapper.Map<C>(B.SomeOtherProp, ops => ops.Items["someOption"] = "someValue");
return new B
{
SubProp1 = subProp1,
SubProp2 = subProp2
};
}
}
This was working fine in AutoMapper 8.0.0 but I'm upgrading to AutoMapper 10.1.1 (last version with .NET framework support).
In this newer version of AutoMapper the overload method to pass IMappingOperationsOptions does not exist anymore.
I could (theoretically) solve this by injecting IMapper in the constructor of the TypeResolver and use that instead of the ResolutionContext's Mapper but that doesn't feel right.
At the moment I solved the issue by temporarily updating the ResolutionContext options, but that also doesn't really feel right.
var subProp1 = context.Mapper.Map<C>(B.SomeProp);
context.Options.Items["someOption"] = "someValue";
var subProp2 = context.Mapper.Map<C>(B.SomeOtherProp);
context.Options.Remove("someOption");
Casting ((IMapper)context.Mapper).Map() crashes so that's not an option either. Is there a more elegant way to achieve this?

Related

AutoMapper ResolutionContext does not contain a definition for engine anymore

After migration from an old version of AutoMapper (before 5) to version 9 there is one spot which causes headache. Old implementation:
.ForMember(a => a.Definition, o =>
{
o.Condition(s => s.TypeId == DocumentationType.Medication);
o.ResolveUsing((d, ctx) => ctx.Engine.Map<MedicationDefinitionContent>(d.Content.MedicationContentData));
})
which uses this extension method:
public static class MappingExtensions
{
public static void ResolveUsing<TType>(this IMemberConfigurationExpression<TType> expression, Func<TType, ResolutionContext, object> map)
{
expression.ResolveUsing(result => map((TType)result.Value, result.Context));
}
}
I fixed the first error that that IMemberConfigurationExpression needs 3 arguments, but then I learned that ResolutionContext does not contain a definition for engine anymore. I looked in the upgrade guide of version 5 and found that the ResolutionContext has been changed, but I do not understand how to fix this. The code seems to be pretty tricky. Can someone help, please?
#Lucian Bargaoanu
Ok, but the member "Definition" is the member wie map with MapFrom(s => s.Content.MedicationContentData). So different to the exception there is already a mapping. The member "Definition" is of type SerialisationHelper a helper class for Json stuff. It also has a mapping.
CreateMap<MedicationDefinitionContent, SerialisationHelper>()
.IgnoreAllUnmapped()
.AfterMap((s, t) => t.Write = s);
And MedicationDefinitionContent has a separate mapping.
CreateMap<MedicationContentData, MedicationDefinitionContent>()
MedicationDefinitionContent is annotated with [JsonObject(MemberSerialization.OptIn)]
so, a direct mapping from MedicationDefinitionContent to "Definition" does not work.
How you see I try to understand it, but maybe it needs more time.

Issues of List mapping by automapper

Im using automapper to object conversion where source is table class and destination is property class.
I'm using .dml to connect database.
App type - Window
Using platform - VS-12 framework 4.5 , automapper version 4.2.1
Issues :- when convert single class object automapper successfully converted but when im using list then it return zero.
In Config class-
public static Initialize();
Mapper.CreateMap<Source, destination>().ReverseMap();
Mapper.CreateMap<List<Source>, List<destination>>().ReverseMap();
In code-
//It run successfully
Mapper.map(result, objdestination);
//It not run work and anot giving any exception
Mapper.map(listresult, listdestination);
Thanks in advance.
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap< Source, destination>().ReverseMap();
});
config.AssertConfigurationIsValid(); // check if configuration valid.
IMapper mapper = config.CreateMapper();
var appProduct = mapper.Map<List<destination>>(sourceObj);

Trying "Messaging via attribute" from the documentation

I'm trying to get the hung of catel but have a problem.
Trying "Messaging via attribute" gets an compile error.
'Catel.MVVM.ViewModelBase.GetService(object)' is obsolete: 'GetService is no longer >recommended. It is better to inject all dependencies (which the TypeFactory fully supports) >Will be removed in version 4.0.0.'
private void OnCmdExecute()
{
var mediator = GetService<IMessageMediator>();
mediator.SendMessage("Test Value");
}
[MessageRecipient]
private void ShowMessage(string value)
{
var messageService = GetService<IMessageService>();
messageService.Show(value);
}
I'm using 3.9.
A hint and a code snippet whould be good help.
Thanks for your attention.
The GetService is marked obsolete. You have 2 options:
1) If you are using a view model, simply let the services be injected in the constructor:
private readonly IMessageMediator _messageMediator;
private readonly IMessageService _messageService;
public MyViewModel(IMessageMediator messageMediator, IMessageService messageService)
{
Argument.IsNotNull(() => messageMediator);
Argument.IsNotNull(() => messageService);
_messageMediator = messageMediator;
_messageService= messageService;
}
2) Use the GetDependencyResolver extension method:
var dependencyResolver = this.GetDependencyResolver();
var messageMediator = dependencyResolver.Resolve<IMessageMediator>();
Solution 1 is the recommended way.
Thanks for your answer.
I also found a good example in the "Catel.Examples" solution, link to download

Catel Auto Register Attributes with multiple instances

we are developing a GUI Plug-In Framework using Catel.MVVM.
Single Plugins should be loaded dynamically using the "ServiceLocatorRegistration" Attribute.
Example:
[ServiceLocatorRegistration(typeof(IInitializable), ServiceLocatorRegistrationMode.SingletonInstantiateWhenRequired, "SamplePlugin")]
In our bootstrapper we load all Plugin assemblies into the default AppDomain:
Catel.Windows.Controls.MVVMProviders.Logic.UserControlLogic.DefaultSkipSearchingForInfoBarMessageControlValue = true;
Catel.Windows.Controls.MVVMProviders.Logic.UserControlLogic.DefaultCreateWarningAndErrorValidatorForViewModelValue = false;
IoCConfiguration.DefaultServiceLocator.AutoRegisterTypesViaAttributes = true;
IoCConfiguration.DefaultServiceLocator.CanResolveNonAbstractTypesWithoutRegistration = true;
foreach (
var file in
BaseDirectory.GetFiles("*.dll", SearchOption.AllDirectories)
.Where(f => IsNetAssembly(f.FullName))
.Where(f => !f.FullName.EndsWith("resources.dll"))
.AsParallel())
{
try
{
var asm = Assembly.ReflectionOnlyLoadFrom(file.FullName);
}
catch { }
}
Then we try to initialize them by calling
var initializables = ServiceLocator.Default.ResolveTypes();
foreach(var initializable in initializables)
initializable.Initialize();
But even if we have the plugin assemblies loaded in the AppDomain, we dont get all Classes with the ServiceLocatorRegistration attribute.
Is there any was to resolve all classes that have the example attribute set as above?
Thanks in advance!
The problem is probably because the assemblies containing the types that use the registration are not loaded into the AppDomain yet. There are a few things you can consider:
1) Use AppDomainExtensions.PreloadAssemblies
2) Use the type somehow (like Console.WriteLine(typeof(TypeFromAssembly).FullName))
I wouldn't recommend the second one because it goes against your plug-in architecture.
Resolved this issue myself. Mistake was probably the linevar asm = Assembly.ReflectionOnlyLoadFrom(file.FullName);
After replacing this line withAppDomain.CurrentDomain.LoadAssemblyIntoAppDomain(file.FullName); everything works as expected.
Thanks Geert for pointing to the right direction!

EF 5 Re-Use entity configuration

I'm trying to re-use some of the model configurations on several entities that implements a interface.
Check this code:
public static void ConfigureAsAuditable<T>(this EntityTypeConfiguration<T> thisRef)
where T : class, IAuditable
{
thisRef.Property(x => x.CreatedOn)
.HasColumnName("utctimestamp")
.IsRequired();
thisRef.Property(x => x.LastUpdate)
.HasColumnName("utclastchanged")
.IsRequired();
} // ConfigureAsAuditable
as you can see I'm trying to call the extension method "ConfigureAsAuditable" on my onmodelcreating method like this:
EntityTypeConfiguration<Account> conf = null;
conf = modelBuilder.Entity<Account>();
conf.ToTable("dbo.taccount");
conf.ConfigureAsAuditable();
When debugging i get this exception:
The property 'CreatedOn' is not a declared property on type
'Account'. Verify that the property has not been explicitly excluded
from the model by using the Ignore method or NotMappedAttribute data
annotation. Make sure that it is a valid primitive property.
Thanks in advance :)
PD:
I'm using EF 5-rc, VS 2011 and .NET Framework 4.5
I think a better approach would be to implement your own derived version of EntityTypeConfiguration. For example:
public class MyAuditableConfigurationEntityType<T> : EntityTypeConfiguration<T>
where T : class, IAuditable{
public bool IsAuditable{get;set;}
}
Then, when building your model, use that new type:
var accountConfiguration = new MyAuditableConfigurationEntityType<Account>();
accountConfiguration.IsAuditable = true; // or whatever you need to set
accountConfiguration.(HasKey/Ignore/ToTable/Whatever)
modelBuilder.Configurations.Add(accountConfiguration);

Resources