Home > Enterprise >  HttpClient Get with file in body
HttpClient Get with file in body

Time:07-02

I have to call an external API via a HttpGet that requires me to send a file in the body. I realize that this is a bad API design but since it's external, I have no influence over it and cannot change it.

I let our internal users upload a csv file via:

<div >
    <label  asp-for="File"></label>
    <div >
        <input  asp-for="File" accept=".csv" />
    </div>
</div>

<form-group-button asp-text="Upload" asp-glyphicon="cloud-upload" />

The controller takes this file and continues the processing:

public async Task<IActionResult> UploadCsv(UploadCsvViewModel vm)
{
    if (!this.ModelState.IsValid)
    {
        return this.View("Index");
    }

    var command = this.mapper.Map<GetMemberStatusCommand>(vm);
    await this.mediator.Send(command);

    return null; // TODO
}

The model:

public class UploadCsvViewModel
{
    [Required]
    public IFormFile File { get; set; }
}

The command (not sure if I really need to map it to a string):

public class GetMemberStatusCommand : IRequest<string>, IMapFrom<UploadCsvViewModel>
{
    public byte[] FileContent { get; set; }

    public void Mapping(Profile profile)
    {
        profile.CreateMap<UploadCsvViewModel, GetMemberStatusCommand>()
            .ForMember(dest => dest.FileContent, act => act.MapFrom<CsvFileContentResolver>());
    }
}

The resolver:

public class CsvFileContentResolver : IValueResolver<UploadCsvViewModel, GetMemberStatusCommand, byte[]>
{
   public byte[] Resolve(UploadCsvViewModel source, GetMemberStatusCommand destination, byte[] destMember, ResolutionContext context)
    {
        using var memoryStream = new MemoryStream();
        source.File.CopyToAsync(memoryStream);
        return memoryStream.ToArray();
    }
}

The CommandHandler

public class GetMemberStatusCommandHandler : IRequestHandler<GetMemberStatusCommand, string>
{
private readonly HttpClient httpClient;
private readonly ISysParamService sysParamService;

public GetMemberStatusCommandHandler(HttpClient httpClient, ISysParamService sysParamService)
{
    this.httpClient = httpClient;
    this.sysParamService = sysParamService;
}

public Task<string> Handle(GetMemberStatusCommand request, CancellationToken cancellationToken)
{
    var apiUrl = this.sysParamService.GetParamValueAs<string>(SysParamConst.API_URL);

    var byteArray = Encoding.ASCII.GetBytes("xxx:yyy");
    this.httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));

  
     var httpRequestMessage = new HttpRequestMessage
    {
        Method = HttpMethod.Get,
        RequestUri = new Uri(apiUrl),
        Content = new ByteArrayContent(request.FileContent) { Headers = { ContentType = MediaTypeHeaderValue.Parse("text/csv") }}
    };

    var result = await this.httpClient.SendAsync(httpRequestMessage, cancellationToken);

    return Task.FromResult(""); // TODO
}
}

In this CommandHandler, I need to send the file like I did in Postman, so via a HttpGet, and with key = file and the file as content in the body.

enter image description here

Is it possible to send the IFormData via the Get-method and how? Or do I have to send it as a string, or as a byte[]?

Thanks in advance

Edit: I've rewritten it so that I can send the file as a byte[]. I still need to set the key to the name "file", how is this possible?

CodePudding user response:

Construct the message like this.

var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, apiUrl)
{
    Content = new MultipartFormDataContent
    {
        {
            new ByteArrayContent(request.FileContent),
            "key",
            "test.csv"
        }
    }
};

CodePudding user response:

From the code you provided I see that you have created an object called httpRequestMessage

    var httpRequestMessage = new HttpRequestMessage
    {
        Method = HttpMethod.Get,
        RequestUri = new Uri(apiUrl),
        Content = new StringContent("") // TODO
    };

You can use that with httpClient.Send(httpRequestMessage), that way you should be able to populate the body with a get http request

  • Related