I've been working with AutoMapper and it was quite joyful but for a number of reasons I got to use Mapster in my new project.
As you may know we had a handy configuration for CustomValueResolvers:
CreateMap<Context.Models.Employee, EmployeeDTO>()
.ForMember(dest => dest.CustomValue, opt => opt.MapFrom<EmployeeCustomValueResolver>());
EmployeeCustomValueResolver was a class with its own template you could inject DbContext and read whatever you need and return whatever you want:
public class EmployeeCustomValueResolver: IValueResolver<Context.Models.Employee, EmployeeDTO, List<anyType>>
{
//Read whatever you want from db and return.
}
But now in this Mapster I don't know how to do that.
I have a type config section like this:
TypeAdapterConfig<Employee, EmployeeDTO>.NewConfig()
.Map(dest=>dest.Gates,src=>src.Gates.ToList())
but this is not what I want. I want to create a custom class as a custom value resolver and return my Gates as a result and I don't know how? I need something like AutoMapper ValueResolver.
Any help is appreciated.
Related
I have a pretty big class using entity framework with some list properties as a one to many relationship. I use AutoFixture to create test data and to get rid of circular references I set a lot of 'Without'. But keep copying this same code again and again. I cant figure out how to customize the initial creation. It looks something like this
Works:
var entity = fixture.Build<MyObject>()
.Without(c => c.Cars)
.Without(c => c.Boats)
.Without(c => c.Motorcycles)
.Without(c => c.Skateboards)
.Create();
I would like setup these as defaults for every time I use a fixture to create a MyObject (and then be able to override them in some cases)
I tried creating a class like this
public class Conventions: ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<MyObject>
(c => c
.Without(c => c.Cars)
.Without(c => c.Boats)
.Without(c => c.Motorcycles)
.Without(c => c.Skateboards)
);
And then use it:
var fixture = new Fixture();
fixture.Customize(new Conventions());
var entity = fixture.Build<MyObjec>().Create();
But nope it fails on recursive declarations
The behavior you describe is intended by design. The .Build<T>() customization creates a one-time-use customization that ignores all previously assigned customizations.
If the intention was to just create an instance using a previously applied type customization, then all you need to do is remove the .Build<T>() statement from you test and just use .Create() directly. This will avoid creating the customization from scratch.
var fixture = new Fixture();
fixture.Customize(new Conventions());
var entity = fixture.Create<MyObject>();
Since you are using EntityFramework it is likely that your navigation properties are marked as virtual. You could write a IRequestSpecification that would identify virtual members and use the Omitter to omit all navigation properties.
Another approach to tackle your issue would be to consider changing the design of your domain models. Ask yourself whether it is a valid operation to allow clients of your domain model to "set/replace" the collection of boats for example. If the answer is "no" you might want to change the model so that this rule is reflected in the design itself, i.e. make the setter private and change the collection to a read only collection. If you do this AutoFixture will ignore the navigation properties and you would be able to set their values using the appropriate business rules.
Finally if you still want to reuse a parts of the customization you could extend AutoFixture in a way that would allow this kind of operation. Both Customize<T>() and Build<T>() are employing the IPostprocessComposer<T> interface to compose the inline customizations. You could write an extension method that intervenes in the process and delegates the customization to a third party.
public static class ComposerExtensions
{
public static IPostprocessComposer<T> Using<T>(this IPostprocessComposer<T> source, IPartialPostprocessComposer<T> composer)
{
return composer.Compose(source);
}
}
Now assuming a third party could look like this.
public class MyClassPartialComposer : IPartialPostprocessComposer<MyClass>
{
public IPostprocessComposer<MyClass> Compose(IPostprocessComposer<MyClass> source)
{
return source
.Without(x => x.Cars)
.Without(x => x.Boats);
}
}
Your customization could look like this.
var actual = fixture.Build<MyClass>()
.Using(new MyClassPartialComposer())
.With(x => x.Name, "hello")
.Create();
With this approach you could also compose parts of the inline customization.
Remember though that this last approach is not supported officially by AutoFixture and you'd have to define the extension method and the partial composer implementations yourself.
I'm trying to create a wrapper repository that will be able to use a generic repository based on type.
So far I have:
Startup:
builder.RegisterAssemblyTypes(Assembly.Load("Data"))
.Where(t => t.Namespace.Contains("Repositories"))
.As(t => t.GetInterfaces().FirstOrDefault(i => i.Name == "I" + t.Name))
.InstancePerLifetimeScope();
builder.RegisterType<GenericRepositoryLong<EventRegistrationActivity>>()
.As<IGenericRepositoryLong<ILongEntity>>()
.Keyed<IGenericRepositoryLong<ILongEntity>>(ActivityType.EventRegistration)
.AsSelf()
.InstancePerLifetimeScope();
builder.Register<Func<ActivityType, IGenericRepositoryLong<ILongEntity>>>(c =>
{
var componentContext = c.Resolve<IComponentContext>();
return (activityType) =>
{
var repo = componentContext.ResolveKeyed<IGenericRepositoryLong<ILongEntity>>(activityType);
return repo;
};
});
ActivityRepository is basically a wrapping repository that handles Cache data consistency. It should also use the generic repository to save the entity. The generic repository is working great when injected, but it does not work when I try the following:
public class ActivityRepository: IActivityRepository
{
private readonly Func<ActivityType, IGenericRepositoryLong<ILongEntity>> ActivityRepoFac;
public ActivityRepository(Func<ActivityType, IGenericRepositoryLong<ILongEntity>> activityRepoFac)
{
ActivityRepoFac = activityRepoFac;
}
public async Task CreateActivityAsync(IFeedActivity activity, ActivityType activityType)
{
var repo = ActivityRepoFac(activityType);
...repo code here
}
}
ActivityType is a simple enum, and the error I'm getting is :
The type
'Infra.DataProvider.GenericRepositoryLong`1[Domain.Entities.Activities.EventRegistrationActivity]'
is not assignable to service
'Infra.DataProvider.IGenericRepositoryLong`1[[Domain.ILongEntity, Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
Is what I'm trying to do possible, and if so have I missed something?
Also, is this a good practice?
Would appreciate any help on the matter.
There isn't enough to go on here to decisively say what's up, but the exception is pretty telling.
The registration here is the important part that you'll need to test, and not even with all the keyed and extra settings. Just this:
builder.RegisterType<GenericRepositoryLong<EventRegistrationActivity>>()
.As<IGenericRepositoryLong<ILongEntity>>();
What the exception is saying is that you can't cast GenericRepositoryLong<EventRegistrationActivity> to IGenericRepositoryLong<ILongEntity>.
Put another way, if you did this, it wouldn't compile:
IGenericRepositoryLong<ILongEntity> repo =
new GenericRepositoryLong<EventRegistrationActivity>();
I don't actually see the definition of the GenericRepositoryLong<T> or IGenericRepositoryLong<T> entities so I can't say for sure, but that's what the exception is saying.
Usually this is because the interface is declared like this:
public interface IGenericRepositoryLong<T>
and it's missing the proper variance keyword for what you're trying to do. I'm guessing you probably want
public interface IGenericRepositoryLong<out T>
I would try troubleshooting this in a unit test that doesn't involve Autofac at all. If you were going to manually create all the types and properties and wire them up yourself, does it work? Trying to figure it out whilst also trying to register things and line up Autofac syntax can lead to confusion, like "Is it Autofac doing this, or is it something in my code?"
Finally, unrelated to the question, I did notice you're registering the GenericRepositoryLong<T> both AsSelf and Keyed, which seems weird. I mean, you may actually want to also be able to directly resolve GenericRepositoryLong<T> but given the setup you're showing and how it's very tightly coupled to the activity type, chances are you probably don't want that in there. It won't hurt anything to have it, but it can also lead to confusion if you accidentally resolve something you didn't intend to simply because you added too many services/registrations.
I am using automapper to map my DTOs to Viewmodels, some of my viewmodels have a dependency to a service.
I found a couple of ways to construct the destination object using these dependencies but i wonder if it is possible to just use a global object resolver (UnityContainer in my case)?
my current solution is this:
config.CreateMap<SurveyDTO, SurveyViewModel>()
.ConstructUsing(x => _ObjectResovler.Resolve<SurveyViewModel>())
or alternatively
config.CreateMap<SurveyDTO, SurveyViewModel>()
.ConstructUsingServiceLocator()
But this means that i have to include a line like this in every mapping.
Is there a way to just use the resolver for all mappings without specifying it in the configuration?
I solved it by using
config.ForAllMaps((map, opts) => opts
.ConstructUsing(x => _ObjectResovler.Resolve(map.DestinationType)));
for the servicelocator alternative you could use:
config.ForAllMaps((map, opts) => opts.ConstructUsingServiceLocator());
In my application I need to do many mappings (Domain objects, DTOs, ViewModels etc.) between different pair of objects. I use AutoMapper heavily for the purpose.
So I have a common Mapper class which has methods to map different objects. As Mappings are persisted in the application, I do all my CreateMap() in the static constructor so that the mappings are created only once and are ready by the time I might use them. The class looks like this
public class SomeMapper
{
static SomeMapper()
{
Mapper.CreateMap<SomeType1, SomeOtherType1>();
Mapper.CreateMap<SomeType2, SomeOtherType2>();
Mapper.CreateMap<SomeType3, SomeOtherType3>();
//...
}
public SomeOtherType1 MapSomeHierarchy1(SomeType1 source)
{ //... }
public SomeOtherType2 MapSomeHierarchy2(SomeType2 source)
{ //... }
}
Question 1: What can be a better way to create the mappings? (better in any way - performance, semantics, standard practices etc.)
Question 2: This code is also used in a Console application. In a particular run, it'll not need all the mappings. So, rather than creating all the mappings eagerly, can I create the map at run time if it does not exist already? Something like
public SomeOtherTypeN MapSomeHierarchyN(SomeTypeN source)
{
if (!AlreadyMapped(SomeTypeN, SomeOtherTypeN))
Mapper.CreateMap<SomeTypeN, SomeOtherTypeN>();
return Mapper.Map<SomeOtherTypeN>(source);
}
Is there a simple way to implement the method AlreadyMapped() ?
As you've said, mappings need only be created once during the lifecycle of the application. There are two main changes I would recommend:
Split your mappings into Profiles
These smaller units, and can be unit tested individually, so you can ensure all destination properties are either automatically mapped, explicitly mapped or ignored.
public class MyProfile : Profile
{
protected override void Configure()
{
// Note, don't use Mapper.CreateMap here!
CreateMap<SomeType1, SomeOtherType1>();
}
}
You then load individual profiles, allowing you to define these closer to where they are used in modular applications.
Mapper.AddProfile<MyProfile>();
Profiles can be tested individually:
Mapper.AssertConfigurationIsValid<MyProfile>();
I typically include a unit test with every profile - this way if your source or destination objects change in a way which break your mapping, you'll know about it immediately.
Create Mappings at Startup
While technically you can create mappings at any point during your application's lifecycle, AutoMapper makes various optimisations if you tell it that you're done. Some of these are essential if you perform any complex mappings with inheritance. Rather than creating mappings on the fly:
Mapper.CreateMap<SomeType1, SomeOtherType1>();
Mapper.AddProfile<MyProfile>();
You should load these using Mapper.Initialize instead:
Mapper.Initialize(cfg =>
{
cfg.CreateMap<SomeType1, SomeOtherType1>();
cfg.AddProfile<MyProfile>();
});
If you absolutely must add mappings on the fly, then you can force AutoMapper to perform its optimisations again after adding mappings using Mapper.Configuration.Seal().
Finally, if you're using an IoC container, then you can combine these two techniques by registering all of your Profiles in your AutoMapper container, then using this to locate and register them. Here's an example using Autofac:
// Register Components...
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<MyProfile>().As<Profile>();
// This could also be done with assembly scanning...
builder.RegisterAssemblyTypes(typeof<MyProfile>.Assembly).As<Profile>();
// Build container...
var container = builder.Build();
// Configure AutoMapper
var profiles = container.Resolve<IEnumerable<Profile>>();
Mapper.Initialise(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
Regarding your second question, if you follow my point about creating mappings at startup then you won't need this, but defining a mapping which already exists overwrites the previous mapping, so shouldn't have any effect.
I'm looking for a good way to incorporate settings inside my webapp (asp mvc). I've came across a really nice implementation in NopCommerce. NopCommerce stores the values in a database table, with a name and value. The name is derived from the class and property name (e.g. customersettings.settingname1)
The exact way NopCommerce works with settings can be found in this question: Understanding how Nop Commerce settings are loaded from the database
NopCommerce uses Autofac as DI framework to bind the Settings to the ConfigurationProvider as follows (as I'm correct).
return RegistrationBuilder
.ForDelegate((c, p) => c.Resolve<IConfigurationProvider<TSettings>>().Settings)
.InstancePerHttpRequest()
.CreateRegistration();
In the appropriate classes, you can now use ClientSettings as a parameter, and it's automatically filled with data from the database.
I really like this implementation, because it is very flexible. The problem however is that I'm using Ninject. I've tried several things to get the correct bindings, but can't seem to find the correct implementation. Does anyone have an idea how to get this working?
EDIT:
I found a way to bind ClientSettings directly:
kernel.Bind<ClientSettings>()
.ToMethod(ctx => ctx.Kernel.Get<IConfigurationProvider<ClientSettings>>().Settings)
.InRequestScope();
But is there a way to achieve this?
kernel.Bind<ISettings>()
.ToMethod(ctx => ctx.Kernel.Get<IConfigurationProvider<ISettings>>().Settings)
.InRequestScope();
EDIT 2
I think I'm getting close, but still run into some problems. I create a custom Binding Generator:
public class SettingsBindGenerator : IBindingGenerator
{
static readonly MethodInfo BuildMethod = typeof(SettingsBindGenerator).GetMethod(
"BuildRegistration",
BindingFlags.Static | BindingFlags.NonPublic);
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
var obj = typeof (object).IsAssignableFrom(type);
if (type != null && typeof(ISettings).IsAssignableFrom(type))
{
var buildMethod = BuildMethod.MakeGenericMethod(type);
var methodResult = buildMethod.Invoke(null, new object[]{bindingRoot});
var castedResult = methodResult as IBindingWhenInNamedWithOrOnSyntax<object>;
yield return castedResult;
}
}
static IBindingWhenInNamedWithOrOnSyntax<TSettings> BuildRegistration<TSettings>(IBindingRoot bindingRoot) where TSettings : ISettings, new()
{
return bindingRoot.Bind<TSettings>().ToMethod(
ctx => ctx.Kernel.Get<IConfigurationProvider<TSettings>>().Settings);
}
}
This works for 99%. However, for some reason, buildMethod.Invoke returns an BindingConfigurationBuilder, and not an IBindingWhenInNamedWithOrOnSyntax. Therefor, castedResult is always NULL. Anybody got an idea how to correct this?
LAST EDIT
I don't know why, but suddenly it works! Glad I've finally figured it out. Thanx Remo!
You have several options:
Do it like NopCommerce and scan for the settings classes and call the registration method from your first edit using reflection.
Use the conventions extension to register all classes implementing ISettings using a custom binding generator https://github.com/ninject/ninject.extensions.conventions/wiki/Projecting-Services-to-Bind
Use the conventions extension to register all classes implementing ISettings to bind all interfaces. And add a custom IActivationStrategy to Ninject that does assigns the properties like NopCommerce does.