Presentation layer call a method (CreateEvent) in my application layer. This method use generic parameters :
public async Task<string> CreateEvent<T, TDocument>(T @event)
where T : class
where TDocument : Document
{
using (var scope = _serviceProvider.CreateScope())
{
var myRepository = scope.ServiceProvider.GetRequiredService<ICarrierEventRepository<TDocument>>();
var eventMapped = _mapper.Map<TDocument>(@event);
await myRepository.InsertOneAsync(eventMapped);
return eventMapped.Id.ToString();
}
}
Parameter T is object define in presentation layer and TDocument is abstract class that my entities (Domain layer) inherit.
public abstract class Document : IDocument
{
public ObjectId Id { get ; set ; }
//some other properties....
}
Example of entity :
public class PaackCollection : Document
{
public string ExternalId { get; set; }
public DateTime At { get; set; }
//some other properties....
}
In presentation layer, I call my CreateEvent method like this :
[HttpPost]
public async Task<IActionResult> Post(PayLoadPaackModel payLoadPaackModel)
{
var idCreated = await _carrierEventService.CreateEvent<PayLoadPaackModel, Domain.Entities.MongoDb.PaackCollection>(payLoadPaackModel);
//some code here....
return Ok("OK");
}
It's possible to use type of Domain.Entities.MongoDb.PaackCollection as parameter knowing that it belongs to the domain layer ? Normally presentation layer communicate only with application layer.
Thanks for advices
UPDATE This solution works :
Call CreateEvent :
await _carrierEventService.CreateEvent(paackEventMapped);
public async Task<string> CreateEvent<T>(T @event)
where T : class
{
using (var scope = _serviceProvider.CreateScope())
{
Type typeParameterType = typeof(T);
if (typeParameterType.Equals(typeof(PaackEventDto)))
{
var eventMapped = _mapper.Map<PaackEvent>(@event);
var carrierEventRepository = scope.ServiceProvider.GetRequiredService<ICarrierEventRepository<PaackEvent>>();
await carrierEventRepository.InsertOneAsync(eventMapped);
return eventMapped.Id.ToString();
}
else if (typeParameterType.Equals(typeof(LaPosteEventDto)))
{
var eventMapped = _mapper.Map<LaposteEvent>(@event);
var carrierEventRepository = scope.ServiceProvider.GetRequiredService<ICarrierEventRepository<LaposteEvent>>();
await carrierEventRepository.InsertOneAsync(eventMapped);
return eventMapped.Id.ToString();
}
else
return default;
}
}
Is there another solution to use generic for avoid to have lot of condition to compare object ? Because I can have 50 differents objects...
UPDATE
I found solution to get the DestinationType for mapper :
var destinationMap = _mapper.ConfigurationProvider.GetAllTypeMaps().First(t => t.SourceType == typeParameterType);
var destType = destinationMap.DestinationType;
var eventMapped = _mapper.Map(@event, typeParameterType, destType);
It's working, now how I can get type of carrierEventRepository with destType ?
I try this var repository = typeof(ICarrierEventRepository<>).MakeGenericType(destType);
but I can use method of my repository...
I finally found solution :
To get destination type with Automapper, I use _mapper.ConfigurationProvider.GetAllTypeMaps()
, MakeGenericType
help me to have my ICarrierEventRepository<T>
and with this Post help me to use dynamic keyword for call method InsertOneAsync
.
public async Task<string> CreateEvent<T>(T @event)
where T : class
{
using (var scope = _serviceProvider.CreateScope())
{
//Get destination type
Type typeParameterType = typeof(T);
var destinationMap = _mapper.ConfigurationProvider.GetAllTypeMaps().First(t => t.SourceType == typeParameterType);
var destType = destinationMap.DestinationType;
//Map with destination type
var eventMapped = _mapper.Map(@event, typeParameterType, destType);
//Get repository register in services
var repository = typeof(ICarrierEventRepository<>).MakeGenericType(destType);
dynamic repo = scope.ServiceProvider.GetRequiredService(repository);
//Insert on database
await repo.InsertOneAsync((dynamic)eventMapped);
//Get generate id
return ((dynamic)eventMapped).Id.ToString();
}
}