0

We have an API concerning invoices with invoicePositions. We are currently updating said API to move the currency from individual positions to the parent invoice

APIv1

public record InvoiceRequestV1 {
  public IList<InvoicePositionRequestV1> InvoicePositions {get; init;}
  // [...]
}

public record InvoicePositionRequestV1 {
  public Currency Currency {get; init}
  // [...]
}

APIv2

public record InvoiceRequestV2 {
  public Currency Currency {get; init}
  public IList<InvoicePositionRequestV2> InvoicePositions {get; init;}
  // [...]
}

public record InvoicePositionRequestV1 {
  // [...]
}

Dtos

public record InvoiceDto {
  public Currency Currency {get; init}
  public IList<InvoicePositionDtoV1> InvoicePositions {get; init;}
  // [...]
}

public record InvoicePositionDto {
  public Currency Currency {get; init}
  // [...]
}

AutoMapper Profiles

public class InvoiceDtoProfileV1 : Profile {
  public InvoiceDtoProfile() {
    CreateMap<InvoiceRequestModelV1, InvoiceDto>()
      .ForMember(d => d.Currency, m => m.Ignore());
  }
}
public class InvoicePositionDtoProfileV1 : Profile {
  public InvoiceDtoProfile() {
    CreateMap<InvoiceRequestModelV1, InvoiceDto>();
  }
}

We use AutoMapper to map from the incomming requestModel to our internal dtos. Currently both the InvoiceDto and the InvoicePositionDto have a property for Currency. What we would like to achieve is to use AutoMapper to map InvoiceRequestModelV2 including all positions to an InvoiceDto where all InvoicePositionDtos use the Currency from InvoiceRequestModel. Our current solution uses AutoMapper profiles for the base, but we have to manually update the Currency:

AutoMapper Profiles

public class InvoiceDtoProfileV2 : Profile {
  public InvoiceDtoProfile() {
    CreateMap<InvoiceRequestModelV2, InvoiceDto>();
  }
}
public class InvoicePositionDtoProfileV2 : Profile {
  public InvoiceDtoProfile() {
    CreateMap<InvoiceRequestModelV2, InvoiceDto>()
      .ForMember(d => d.Currency, m => m.Ignore());
  }
}

Controller

invoiceRequestDto = invoiceRequestDto.UpdateCurrencyOnSalesInvoicePositions(salesInvoiceRequestModel.Currency);

ExtensionMethod

public static class InvoiceDtoExtensions {
  public static InvoiceDto UpdateCurrencyOnSalesInvoicePositions(this InvoiceDto invoiceDto, Currency currency) {
    var updatedSalesInvoicePositionDtos = invoiceDto.SalesInvoicePositions
      .Select(invoicePositionDto => invoicePositionDto with { Currency = currency }).ToList();

    return invoiceDto with { InvoicePositions = updatedSalesInvoicePositionDtos };
  }
}

We have tried using an IMappingAction as AfterAction as follows:

public class UpdateCurrencyAction : IMappingAction<InvoiceRequestModelV2, InvoiceDto> {
  public void Process(InvoiceRequestModelV2 source, InvoiceDto destination, ResolutionContext context) =>
    invoiceDto.InvoicePositions = invoiceDto.InvoicePositions.Select(position => position.Currency = currency).ToList();
}

but that fails due to InvoiceDto and InvoicePositionDto being records (immutable). When using the property initialiser invoicePositionDto = invoicePositionDto with { Currency = invoiceDto.Currency };, we see, that the result is not used by AutoMapper.

Is there any way to implement what we want using AutoMapper functionality and C# records?

Answers I have looked into, but found unhelpful include:

Most of these answers were unhelpful, because our InvoicePositionDto does not have a reference to its parent InvoiceDto (dito with RequestModel).

froeschli
  • 2,584
  • 2
  • 27
  • 50

0 Answers0