Why Automapper needs IMapper interface for map? - c#

I have created an extension to map my types that implemented IHaveStandardMapping interface.
public static class AutomapperExtensions
{
public static TDest MapTo<TDest>(this object src, IMapper mapper)
where TDest: IHaveStandardMapping
{
return (TDest)mapper.Map(src, src.GetType(), typeof(TDest));
}
}
And I am using it in my service.
public class ComponentService : IComponentService
{
private readonly PostgresqlDataContext _context;
private readonly IMapper _mapper;
public ComponentService(PostgresqlDataContext context, IMapper mapper)
{
_context = context;
_mapper = mapper;
}
public async Task<ComponentViewModel> GetComponent(string id)
{
var existing = await _context.Components.FirstOrDefaultAsync(s => s.Id == id);
if (existing == null)
throw new EntityNotFoundException("Component");
var result = existing.MapTo<ComponentViewModel>(_mapper);
return result;
}
}
But I need to get IMapper interface for all services.
I should use it in method
existing.MapTo<T>(_mapper);
The old versions were did not need the IMapper interface.
Is there a short way without using IMapper?

The static API is now deprecated. IMapper is used so you can inject the mapper in your controllers/services. I you want to you can create your own service wrapping the IMapper interface, so you can limit your dependency on the IMapper interface to one service only.

Related

Should i use service or repository in cqrs handler?

I have a project where I use mediatr, CQRS and onion architecture.
public class CreateOrderCommandHandler : IRequestHandler<CreateOrderCommand, CreatedOrderDto>
{
private readonly IOrderRepository _orderRepository;
private readonly IProductRepository _productRepository;
private readonly IMapper _mapper;
public CreateOrderCommandHandler(IOrderRepository orderRepository,IProductRepository
productRepository, IMapper mapper)
{
_orderRepository = orderRepository;
_productRepository = productRepository;
_mapper = mapper;
}
public async Task<CreatedOrderDto> Handle(CreateOrderCommand request, CancellationToken
cancellationToken)
{
// _orderRepository.Add(order);
// _ productRepository.Update(product);
}
}
Should CreateOrder Command depend on Product Service instead of ProductRepository?
Should the repository be used in the Handler?
As per your code in the question, it should depend on ProductRepository not on the service, and service is a collection of classes while Reposiriry represents a single class so you cannot inject a service but you can inject a repository.
and by the way, I cannot see any Product Service in your code.

How do I resolve "Unable to resolve service for type '' while attempting to activate ''"

When I attempt requests to a .net core 3.1 WebAPI from Postman I am getting error
System.InvalidOperationException: Unable to resolve service for type 'PaymentsAPI.Repository.PaymentService' while attempting to activate 'PaymentsAPI.Controllers.PaymentController'
'
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddCors(c =>
{
c.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
});
services.AddDbContext<ApplicationDbContext>(o => o.UseSqlServer(Configuration.GetConnectionString("SqlSvrConn")));
services.AddTransient<IAsyncPaymentsService<PaymentDetail>, PaymentService>();
}
IAsyncPaymentsService.cs
public interface IAsyncPaymentsService<TEntity>
{
Task<IEnumerable<TEntity>> GetAllAsync();
}
PaymentService.cs
public class PaymentService : IAsyncPaymentsService<PaymentDetail>
{
private readonly ApplicationDbContext _dbContext;
public async Task<IEnumerable<PaymentDetail>> GetAllAsync()
{
return await _dbContext.PaymentDetails.ToListAsync();
}
}
PaymentController.cs
[ApiController]
[Route("[controller]")]
public class PaymentController : ControllerBase
{
private readonly ApplicationDbContext _context;
private readonly PaymentService _service;
public PaymentController(ApplicationDbContext context, PaymentService service)
{
_context = context;
_service = service;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<PaymentDetail>>> GetAsync()
{
var items = (await _service.GetAllAsync());
return Ok(items);
}
}
I have tried rearranging the order of services in the container but the error still persists. What am I missing ?
The quick fix would be to change the controller constructor to depend on the abstraction instead of the implementation since the abstraction is what was registered with the container.
//...
private readonly ApplicationDbContext _context;
private readonly IAsyncPaymentsService<PaymentDetail> _service;
public PaymentController(ApplicationDbContext context, IAsyncPaymentsService<PaymentDetail> service)
{
_context = context;
_service = service;
}
//...
However, the generic abstraction could derived to a closed type if so desired
public interface IPaymentService : IAsyncPaymentsService<PaymentDetail> {
}
applied to the implementation
public class PaymentService : IPaymentService {
//...omitted for brevity
}
registered with the container
services.AddTransient<IPaymentService, PaymentService>();
and refactored in the controller
//...
private readonly ApplicationDbContext _context;
private readonly IPaymentService _service;
public PaymentController(ApplicationDbContext context, IPaymentService service)
{
_context = context;
_service = service;
}
//...
The only thing you should have to change to make this work is to accept the interface into your controller instead of the concrete service.
public PaymentController(ApplicationDbContext context, IAsyncPaymentsService<PaymentDetail> service)
{...}
This is recommended over taking the concrete type for various reasons such as testing. If you truly need the concrete type, you'd have to instead change your registration to
services.AddTransient<PaymentService>();
and leave your controller's constructor as is.

How to Solve Injections In Constructor With Base Handler Class In CQRS .NET Core

I am trying to create a CQRS-patterned application. I have handler classes to manage my business logic. But the handler constructors have many dependency and this leads to a lot of boilerplate. Is there any solution that allows me to inject all these items in a base handler class and make my handler more pure?
public class Handler : IRequestHandler<Command>
{
private readonly DataContext _context;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly string _value;
private readonly IMapper _mapper;
private readonly IEventBus _bus;
public Handler(
DataContext context,
IHttpContextAccessor httpContextAccessor,
IMapper mapper,
IEventBus bus)
{
_context = context;
_httpContextAccessor = httpContextAccessor;
_mapper = mapper;
_bus = bus;
if (httpContextAccessor.HttpContext != null)
_value = _httpContextAccessor.HttpContext.Items["Value"].ToString();
}
public async Task<Unit> Handle(Command request, CancellationToken cancellationToken)
{
if (true) return Unit.Value;
throw new Exception("Error Message");
}
}
It is a common problem.
It is addressed very well with the Facade Pattern or Facade services.
What you do is you create a new service that works as a wrapper for the rest. In this way you inject only one service.
Single responsibility principle alert
You inject too many services in your class and this is typical code smell for single responsibility principle abuse. You should try to split your functionality in different classes. That would help you write cleaner code.

C# Automapper Generic Mapping

When playing around with AutoMapper I was wondering whether the following is possible to implement like this (haven't been able to set it up correctly).
Base Service:
public class BaseService<T, IEntityDTO> : IService<T, IEntityDTO> where T : class, IEntity
{
private IUnitOfWork _unitOfWork;
private IRepository<IEntity> _repository;
private IMapper _mapper;
public BaseService(IUnitOfWork unitOfWork, IMapper mapper)
{
_unitOfWork = unitOfWork;
_repository = unitOfWork.Repository<IEntity>();
_mapper = mapper;
}
public IList<IEntityDTO> GetAll()
{
return _mapper.Map<IList<IEntityDTO>>(_repository.GetAll().ToList());
}
}
Concrete Service:
public class HotelService : BaseService<Hotels, HotelsDTO>, IHotelService
{
private IUnitOfWork _unitOfWork;
private IRepository<Hotels> _hotelsRepository;
private IMapper _mapper;
public HotelService(IUnitOfWork unitOfWork, IMapper mapper) : base(unitOfWork, mapper)
{
_unitOfWork = unitOfWork;
_hotelsRepository = unitOfWork.Repository<Hotels>();
_mapper = mapper;
}
}
Current mappings:
public class AutoMapperProfileConfiguration : Profile
{
protected override void Configure()
{
CreateMap<Hotels, HotelsDTO>().ReverseMap();
}
}
I'm kindly clueless on how the mapping should be done. Anyone any advice or is this just not the way to go?
You can specify DTO type in BaseService as generic parameter:
public class BaseService<T, TDTO> : IService<T, TDTO>
where T : class, IEntity
where TDTO : class, IEntityDTO
{
private IRepository<T> _repository;
...
...
public IList<TDTO> GetAll()
{
return _mapper.Map<IList<TDTO>>(_repository.GetAll().ToList());
}
}
Managed to solve my problem with the following line of code which looks up the mapping of the passed entity to the basecontroller.
public List<TDTO> GetAll()
{
var list = _repository.GetAll().ToList();
return (List<TDTO>)_mapper.Map(list, list.GetType(), typeof(IList<TDTO>));
}

How to specify what named service instance to inject into a controller with StructureMap

Microsoft Unity DI offers a feature where you can register multiple objects for the same interface and give them a name. Then in your constructor you can use an attribute with the argument to specify by name which object you want to inject.
I am wondering how to achieve this same functionality using StructureMap.
Example:
container
.RegisterType<IMappingEngine, MappingEngine>("MappingEngineOne", new HierarchicalLifetimeManager(), new InjectionConstructor(typeof(MappingEngineOneConfiguration)))
.RegisterType<IMappingEngine, MappingEngine>("MappingEngineTwo", new HierarchicalLifetimeManager(), new InjectionConstructor(typeof(MappingEngineTwoConfiguration)))
....
public class MyServiceAgent {
private readonly IMappingEngine _mapper;
public MyServiceAgent([Dependency("MappingEngineOne")] IMappingEngine mapper) {
_mapper = mapper;
}
}
public class MyOtherServiceAgent {
private readonly IMappingEngine _mapper;
public MyOtherServiceAgent ([Dependency("MappingEngineTwo")] IMappingEngine mapper) {
_mapper = mapper;
}
}

Categories