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