Search code examples
c#.net-coredomain-driven-designautomapper

Can I use type of domain layer entities in presentation layer?


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...


Solution

  • 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();
       }
    }