How and where to implement automapper in WPF application - c#

I haveBusinessLayer, DTO library,DataService, EntityModel(wher EDMX sits), DTO library refers to both business and data layer. I am trying to implement automapper in data layer, want to map entity object to DTO object and return DTO from the dataService library.
Currently am doing this way
public class DataService
{
private MapperConfiguration config;
public DataService()
{
IMapper _Mapper = config.CreateMapper();
}
public List<Dto.StudentDto> Get()
{
using(var context = new DbContext().GetContext())
{
var studentList = context.Students.ToList();
config = new MapperConfiguration(cfg => {
cfg.CreateMap<Db.Student, Dto.StudentDto>();
});
var returnDto = Mapper.Map<List<Db.Student>, List<Dto.StudentDto>>(studentList);
return returnDto;
}
}
}
How can I move all the mappings to one class and automapper should initialize automatically when call to dataserive is made?

Is it good practice to use AutoMapper in data layer?
Yes.
How can I move all the mappings to one class and automapper should initialize automatically when call to dataserive is made?
You could just create a static class that creates the mappings once:
public static class MyMapper
{
private static bool _isInitialized;
public static Initialize()
{
if (!_isInitialized)
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Db.Student, Dto.StudentDto>();
});
_isInitialized = true;
}
}
}
Make sure that you use this class in your data service:
public class DataService
{
public DataService()
{
MyMapper.Initialize();
}
public List<Dto.StudentDto> GetStudent(int id)
{
using (var context = new DbContext().GetContext())
{
var student = context.Students.FirstOrDefault(x => x.Id == id)
var returnDto = Mapper.Map<List<Dto.StudentDto>>(student);
return returnDto;
}
}
}
Dependending on how you actually host the DAL, you might be able to call the Initialize() method of your custom mapper class from the Main() method of an executable or from somewhere else than the constructor of your DataService class.

Use AutoMapper.Mapper.CreateMap on OnAppInitialize. You can do the implementation of course in an own static class for better style.
There is really no more magic in this - because you only have to register (CreateMap) the mappings one time.
initialize automatically when call to dataserive is made?
You can of course register it too in the constructor.
Here you can take a look at another sample - how to use register in one or two of many extended ways.
In the end AutoMapper should make your life easier and not harder. In my opinion the best way is to register everything at one point - when starting the application.
But you also can do it on demand like seperating each CreateMapin the constructor.
Both ways - just make sure you just call it once.

Related

How to configure dependency injection container with Func<T, Result>?

BusinessAction is used to represent an action that can be performed by a user. Each action is related to the specific entity, so if for example, that entity is Order, business actions could be CancelOrder, IssueRefund, etc.
public abstract class BusinessAction<T>
{
public Guid Id { get; init; }
public Func<T, bool> IsEnabledFor { get; init; }
}
public class CancelOrderAction : BusinessAction<Order>
{
public CancelOrderAction ()
{
Id = Guid.Parse("0e07d05c-6298-4c56-87d7-d2ca339fee1e");
IsEnabledFor = o => o.Status == OrderStatus.Active;
}
}
Then I need to group all actions related to the specific type.
public interface IActionRegistry
{
Task<IEnumerable<Guid>> GetEnabledActionIdsForAsync(Guid entityId);
}
public class ActionRegistry<T> : IActionRegistry
where T : BaseEntity
{
private readonly IEnumerable<BusinessAction<T>> _actions;
private readonly IRepository<T> _repository;
public ActionRegistry(IEnumerable<BusinessAction<T>> actions, IRepository<T> repository)
{
_actions = actions;
_repository = repository;
}
public async Task<IEnumerable<Guid>> GetEnabledActionIdsForAsync(Guid entityId)
{
var entity = await _repository.FindByIdAsync(entityId);
return entity == null
? Enumerable.Empty<Guid>()
: _actions.Where(a => a.IsEnabledFor(entity)).Select(a => a.Id);
}
}
Finally, there is an API endpoint that receives entity type (some enumeration that is later on mapped to real .NET type) and ID of an entity. The API endpoint is responsible to return action IDs that are enabled for the current state of the entity.
public class RequestHandler : IRequestHandler<Request, IEnumerable<Guid>>>
{
private readonly Func<Type, IActionRegistry> _registryFactory;
public RequestHandler(Func<Type, IActionRegistry> registryFactory)
{
_registryFactory = registryFactory;
}
public async Task<IEnumerable<Guid>> Handle(Request request, CancellationToken cancellationToken)
{
var type = request.EntityType.GetDotnetType();
var actionRegistry = _registryFactory(type);
var enabledActions = await actionRegistry.GetEnabledActionIdsForAsync(request.EntityId);
return enabledActions;
}
}
The question is: How can I configure the dependency injection container in ASP.NET (using default option or Autofac) so that Func<Type, IActionRegistry> can be resolved?
For parameters in ActionRegistry<T> I guess I can do:
builder.RegisterAssemblyTypes().AsClosedTypesOf(typeof(BusinessAction<>));
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
But, how can I configure Func<Type, IActionRegistry> so that I am able to automatically connect a request for Order with ActionRegistry<Order>? Is there a way to do that or I will need to manually configure the factory by writing some switch statement based on type (and how will that look)?
Is there a better way to achieve what I need here? The end goal is that once I have runtime type, I can get a list of business actions related to that type as well as a repository (so that I can fetch entity from DB).
What you're trying to do is possible, but it's not a common thing and isn't something magic you'll get out of the box. You'll have to write code to implement it.
Before I get to that... from a future perspective, you might get help faster and more eyes on your question if your repro is far more minimal. The whole BusinessAction<T> isn't really needed; the RequestHandler isn't needed... honestly, all you need to repro what you're doing is:
public interface IActionRegistry
{
}
public class ActionRegistry<T> : IActionRegistry
{
}
If the other stuff is relevant to the question, definitely include it... but in this case, it's not, so adding it in here just makes the question harder to read through and answer. I know I, personally, will sometimes just skip questions where there's a lot of extra stuff because there are only so many hours in the day, you know?
Anyway, here's how you'd do it, in working example form:
var builder = new ContainerBuilder();
// Register the action registry generic but not AS the interface.
// You can't register an open generic as a non-generic interface.
builder.RegisterGeneric(typeof(ActionRegistry<>));
// Manually build the factory method. Going from reflection
// System.Type to a generic ActionRegistry<Type> is not common and
// not directly supported.
builder.Register((context, parameters) => {
// Capture the lifetime scope or you'll get an exception about
// the resolve operation already being over.
var scope = context.Resolve<ILifetimeScope>();
// Here's the factory method. You can add whatever additional
// enhancements you need, like better error handling.
return (Type type) => {
var closedGeneric = typeof(ActionRegistry<>).MakeGenericType(type);
return scope.Resolve(closedGeneric) as IActionRegistry;
};
});
var container = builder.Build();
// Now you can resolve it and use it.
var factory = container.Resolve<Func<Type, IActionRegistry>>();
var instance = factory(typeof(DivideByZeroException));
Assert.Equal("ActionRegistry`1", instance.GetType().Name);
Assert.Equal("DivideByZeroException", instance.GetType().GenericTypeArguments[0].Name);

Telling injected automapper to use specific mapping profile in map function

In some cases one of my application services has to generate DTOs with anonymized data for the frontend. The idea was to use different AutoMapper profiles to either map the domain object to the DTO with all properties mapped or the anonymized DTO.
I generated these two profiles and injected them into the service. The AutoMapper is also injected into the service as IMapper and contains all mapping profiles of the application.
What I need now is to tell the mapper to use one specific profile in a call of the Map-function.
Something like this:
var anonymizedDto = _autoMapper.Map<SourceType, DestinationType>
(sourceObject, ops => ops.UseMappingProfile(_anonymizedMapingProfile));
var normalDto = _autoMapper.Map<SourceType, DestinationType>
(sourceObject, ops => ops.UseMappingProfile(_normalMappingProfile));
Is this possible and if yes: how?
As far as i know, you can not change the profile when you call Map.
What you can do is inject two mappers that have been configured with different profiles.
public class MyService : IService {
private readonly IMappingEngine _defaultMapper;
private readonly IMappingEngine _anonymousMapper;
public MyService(IMappingEngine defaultMapper, IMappingEngine anonymousMapper) {
_defaultMapper = defaultMapper;
_anonymousMapper = anonymousMapper;
}
public MyDto GetDefault() {
return _defaultMapper.Map<MyDto>(sourceObject);
}
public MyDto GetAnonymous() {
return _anonymousMapper.Map<MyDto>(sourceObject);
}
}
In your dependency container, set up the constructor injection to respect the name of the ctor parameter. For example with StructureMap:
public void ConfigureAutoMappers(ConfigurationExpression x) {
// register default mapper (static mapping configuration)
Mapper.Configuration.ConstructServicesUsing(t => container.GetInstance(t));
Mapper.Configuration.AddProfile<DefaultProfile>();
var defaultAutomapper = Mapper.Engine
x.For<IMappingEngine>().Use(() => defaultAutoMapper).Named("DefaultAutoMapper");
// register anonymous mapper
var anonConfig = new AnonConfigurationStore( // class derived from ConfigurationStore
new TypeMapFactory(),
AutoMapper.Mappers.MapperRegistry.AllMappers()
);
anonConfig.ConstructServicesUsing(container.GetInstance);
var anonAutoMapper = new MappingEngine(anonConfig);
x.For<IMappingEngine>().Add(anonAutoMapper).Named("AnonAutoMapper");
// Inject the two different mappers into our service
x.For<IService>().Use<MyService>()
.Ctor<IMappingEngine>("defaultMapper").Named("DefaultAutoMapper")
.Ctor<IMappingEngine>("anonymousMapper").Named("AnonAutoMapper");
}

AutoMapper 4.2 and Ninject 3.2

I'm updating a project of mine to use AutoMapper 4.2, and I'm running into breaking changes. While I seem to have resolved said changes, I'm not entirely convinced I've done so in the most appropriate way.
In the old code, I have a NinjectConfiguration, and an AutoMapperConfiguration class that are each loaded by WebActivator. In the new version the AutoMapperConfiguration drops out and I instead instance a MapperConfiguration directly in the NinjectConfiguration class where the bindings are happening, like so:
private static void RegisterServices(
IKernel kernel) {
var profiles = AssemblyHelper.GetTypesInheriting<Profile>(Assembly.Load("???.Mappings")).Select(Activator.CreateInstance).Cast<Profile>();
var config = new MapperConfiguration(
c => {
foreach (var profile in profiles) {
c.AddProfile(profile);
}
});
kernel.Bind<MapperConfiguration>().ToMethod(
c =>
config).InSingletonScope();
kernel.Bind<IMapper>().ToMethod(
c =>
config.CreateMapper()).InRequestScope();
RegisterModules(kernel);
}
So, is this the appropriate way of binding AutoMapper 4.2 using Ninject? It seems to be working so far, but I just want to make sure.
In before IMapper interface didn't existed in the library so you had to implement interface and class below and bound them as a singleton pattern.
public interface IMapper
{
T Map<T>(object objectToMap);
}
public class AutoMapperAdapter : IMapper
{
public T Map<T>(object objectToMap)
{
//Mapper.Map is a static method of the library!
return Mapper.Map<T>(objectToMap);
}
}
Now you simply bind library's IMapper interface to single instance of mapperConfiguration.CreateMapper()
The Problem with your code tho, you should use a single instance(or as Ninject says, a constant) bind.
// A reminder
var config = new MapperConfiguration(
c => {
foreach (var profile in profiles) {
c.AddProfile(profile);
}
});
// Solution starts here
var mapper = config.CreateMapper();
kernel.Bind<IMapper>().ToConstant(mapper);

How to configure Auto mapper in class library project?

I am using auto mapping first time.
I am working on c# application and I want to use auto mapper.
(I just want to know how to use it, so I don't have asp.net app neither MVC app.)
I have three class library projects.
I want to write transfer process in the service project.
So I want to know how and where should I configure the Auto Mapper ?
So based on Bruno's answer here and John Skeet's post about singletons I came up with the following solution to have this run only once and be completely isolated in class library unlike the accepted answer which relies on the consumer of the library to configure the mappings in the parent project:
public static class Mapping
{
private static readonly Lazy<IMapper> Lazy = new Lazy<IMapper>(() =>
{
var config = new MapperConfiguration(cfg => {
// This line ensures that internal properties are also mapped over.
cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
cfg.AddProfile<MappingProfile>();
});
var mapper = config.CreateMapper();
return mapper;
});
public static IMapper Mapper => Lazy.Value;
}
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Source, Destination>();
// Additional mappings here...
}
}
Then in your code where you need to map one object to another you can just do:
var destination = Mapping.Mapper.Map<Destination>(yourSourceInstance);
NOTE: This code is based on AutoMapper 6.2 and it might require some tweaking for older versions of AutoMapper.
You can place the configuration anywhere:
public class AutoMapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(x =>
{
x.AddProfile<MyMappings>();
});
}
}
public class MyMappings : Profile
{
public override string ProfileName
{
get { return "MyMappings"; }
}
protected override void Configure()
{
......
}
But it has to be called by the application using the libraries at some point:
void Application_Start()
{
AutoMapperConfiguration.Configure();
}
Nobody outside of your library has to configure AutoMapper
I recommend that you use the instance based approach using an IMapper. That way no one outside your library has to call any configuration method. You can define a MapperConfiguration and create the mapper from there all inside the class library.
var config = new MapperConfiguration(cfg => {
cfg.AddProfile<AppProfile>();
cfg.CreateMap<Source, Dest>();
});
IMapper mapper = config.CreateMapper();
// or
IMapper mapper = new Mapper(config);
var dest = mapper.Map<Source, Dest>(new Source());
Marko's answer is correct.
We can also go by a below simple solution.
public static class ObjectMapper
{
public static IMapper Mapper
{
get
{
return AutoMapper.Mapper.Instance;
}
}
static ObjectMapper()
{
CreateMap();
}
private static void CreateMap()
{
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<SourceClass, DestinationClass>();
});
}
}
And we can use it like.
public class SourceClass
{
public string Name { get; set; }
}
public class DestinationClass
{
public string Name { get; set; }
}
SourceClass c1 = new SourceClass() { Name = "Mr.Ram" };
DestinationClass c2 = ObjectMapper.Mapper.Map<DestinationClass>(c1);
I have used the Patel Vishal's solution and customized it to my needs.
It's a generic class which makes sure only one instance of mapping is saved in memory per object mapping.
TModel - is a DTO object
TData - is a Database table object in Entity Framework
DTO.IBaseModel - is a base class for DTO object which has one property: ID
IBaseModel - is a base class for the entity framework database entity with ID property only
public static class ObjectMapper<TModel, TData>
where TModel : class, DTO.IBaseModel, new()
where TData : class, IBaseModel, new()
{
private static readonly MapperConfiguration _mapperConfiguration;
public static IMapper Mapper => new Mapper(_mapperConfiguration);
static ObjectMapper()
{
_mapperConfiguration ??= CreateMap();
}
private static MapperConfiguration CreateMap()
{
return new (cfg =>
{
cfg.CreateMap<TData, TModel>();
});
}
}
I am using this class in a BaseService<TData, TModel> (Service/Repository pattern) as such:
public virtual TModel Convert(TData t)
{
return ObjectMapper<TModel, TData>.Mapper.Map<TModel>(t);
}
As you can see, it's a virtual method. Mapping can be overwritten, if customization required by the inheriting Service.
I have come across this kind of requirement as well. What I have done in .Net 6.0 is, I create a library project and create the profile class:
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<Entity, Dto>();
CreateMap<Dto, Entity>();
......
}
}
while in the api or web project, I just create a child class to inherit from the profile above, and register it in startup.cs services.AddAutoMapper(typeof(Startup));.

Pass multiple mock objects to a method

I have a method CreateAccount to test. I am using Moq for the same.
Under CreateAccount method, there are multiple table insertion methods which belongs to two classes AccountRepository and BillingRepository
I have setup the Moq but don't know how to use multiple moq objects.
Below is some code snippet
Mock<AccountRepository> moq = new Mock<AccountRepository>();
Mock<BillingRepository> moqBill = new Mock<BillingRepository>();
moq.Setup(x => x.AddTable_1(new AddTable_1 { }));
moq.Setup(x => x.AddTable_2(new AddTable_2 { }));
moqBill.Setup(x => x.Table_3());
CreateAccount method takes four parameters and its under ApplicationService class
public class ApplicationService
{
public CreateAccountServiceResponse CreateAccount(AuthenticateApp App, CustomerInfo Customer, ServiceInfo Service, Optional op)
{
// SOME VALIDATION CODE
//.....................
// SOME CODE TO SAVE DATA INTO TABLES
obj_1.AddTable_1(objdata_1);
obj_1.AddTable_2(objdata_2);
obj_2.AddTable_3(objdata_3);
}
}
Please suggest some solution. How can these three methods will be skipped ?
Thanks in advance.
You have to provide some means to inject obj_1 and obj_2, since they seem to represent your instances of AccountRepository and BillingRepository, resp.
Typically, you might want to do this by using constructor injection. Extending the snippet you provided, this might look like this:
public class ApplicationService
{
private readonly AccountRepository _accountRepository;
private readonly BillingRepository _billingRepository;
public ApplicationService(AccountRepository accountRepository, BillingRepository billingRepository)
{
_accountRepository = accountRepository;
_billingRepository = billingRepository;
}
public CreateAccountServiceResponse CreateAccount(AuthenticateApp App, CustomerInfo Customer, ServiceInfo Service, Optional op)
{
// SOME VALIDATION CODE
//.....................
// SOME CODE TO SAVE DATA INTO TABLES
_accountRepository.AddTable_1(objdata_1);
_accountRepository.AddTable_2(objdata_2);
_billingRepository.AddTable_3(objdata_3);
}
}
Now you can inject your mocks into the class under test:
public void CreateAccount_WhenCalledLikeThis_DoesSomeCoolStuff()
{
var accountRepoMock = new Mock<AccountRepository>();
// set it up
var billingRepository = new Mock<BillingRepository>();
// set it up
var appService = new ApplicationService(accountRepoMock.Object, billingRepoMock.Objcet);
// More setup
// Act
var response = appService.CreateAccount(...);
// Assert on response and/or verify mocks
}

Categories

Resources