Home > Software design >  How can to map to a wrapper class using Mapster?
How can to map to a wrapper class using Mapster?

Time:05-25

Based on my project I need to create a wrapper for “IFormFile”, Actually I created a “AppFileProxy” class and “IAppFile” interface for this purpose :

IAppFile.cs :

public interface IAppFile
{
    string Name { get; }

    string FileName { get; }

    string ContentType { get; }

    long Length { get; }

    void CopyTo(Stream target);
    Task CopyToAsync(Stream target, CancellationToken cancellationToken = default);
    Stream OpenReadStream();
}

AppFileProxy.cs :

public class AppFileProxy : IAppFile
{
    private readonly IFormFile _formFile;

    public AppFileProxy(IFormFile formFile)
    {
        _formFile = formFile ?? throw new ArgumentNullException(nameof(formFile));
    }

    public string Name => _formFile.Name;

    public string FileName => _formFile.FileName;

    public string ContentType => _formFile.ContentType;

    public long Length => _formFile.Length;

    public void CopyTo(Stream target)
    {
        _formFile.CopyTo(target);
    }

    public Task CopyToAsync(Stream target, CancellationToken cancellationToken = default)
    {
        return _formFile.CopyToAsync(target, cancellationToken);
    }

    public Stream OpenReadStream()
    {
        return _formFile.OpenReadStream();
    }
}

Now, I want to Map “IFormFile” to “IAppFile” by using Mapster in the action controller as shown below :

CompanyDto.cs :

public class CompanyDto
{
    public string Name { get; set; }
    public IFormFile Logo { get; set; }
}

CompanyMapDto.cs :

public class CompanyMapDto : IRegister
{
    public int Id { get; set; }
    public string Name { get; set; }

    public IAppFile Logo { get; set; }

    public void Register(TypeAdapterConfig config)
    {
        config.ForType<CompanyDto, CompanyMapDto>()
                .Map(dest => dest.Logo, src => new AppFileProxy(src.Logo));
    }
}

action controller :

[HttpPost]
[Route("[controller]/[action]")]
public async Task<IActionResult> AddCompanyWithLogo([FromForm]CompanyDto dto)
{
    CompanyMapDto company = dto.Adapt<CompanyMapDto>();

    var stream = company.Logo.OpenReadStream();

    return Ok();
}

But When I call action I get exception error for OpenReadStream() method :

System.NotImplementedException: The method or operation is not implemented.
   at GeneratedType_1.OpenReadStream()
   at MapsterInDotNet.Controllers.CompaniesController.AddCompanyWithLogo(CompanyDto dto) in C:\Users\Mohsen\source\repos\UseMapsterInDotNet\MapsterInDotNet\MapsterInDotNet\Controllers\CompaniesController.cs:line 52
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

enter image description here

How do I resolve this?

CodePudding user response:

Well. I managed to make it work. You have to explicitly configurate mapping from IAppFile to IFormFile.

So instead of your configuration:

config.ForType<CompanyDto, CompanyMapDto>()
    .Map(dest => dest.Logo, src => new AppFileProxy(src.Logo));

Use this:

TypeAdapterConfig<IFormFile, IAppFile>.ForType() // Or NewConfig()
    .MapWith(src => new AppFileProxy(src));
  • Related