Quando queremos enviar um objeto com os parâmetros necessários para um requisição Post em uma API basta usar o método HttpClientJsonExtensions.PostAsJsonAsync(), mas as coisas mudam um pouco quando queremos enviar também arquivos nesta requisição, pois o formato json não suporta um parâmetro de arquivo.
A forma mais comum para enviar formulários que contém arquivos, para uma API, é utilizando multipart/form-data, que é suportado pelo protocolo http.
No ASP.NET não temos algo como PostAsMultipartFormDataAsync(). Eu utilizo o seguinte código para converter objetos, com parâmetros e arquivos, para um MultiPartFormDataContent, para então enviá-lo à API.
public class MultipartFormDataContentParser<T>
{
private T _obj;
public MultipartFormDataContentParser(T obj)
{
_obj = obj;
}
public MultipartFormDataContent Parse()
{
var formContent = new MultipartFormDataContent();
var genericFileName = "Filename";
var propertyInfos = typeof(T).GetProperties();
// Mount MultipartForm
foreach (var propertyInfo in propertyInfos)
{
var value = propertyInfo.GetValue(_obj);
if (value is byte[] ||
value is Stream ||
value is List<Stream> ||
value is List<byte[]>)
{
if (value is List<Stream> listStream)
{
foreach (var file in listStream)
if(file != null)
formContent.Add(new StreamContent(file), propertyInfo.Name, genericFileName);
}else if (value is List<byte[]> listByteArray)
{
foreach (var file in listByteArray)
if(file != null)
formContent.Add(new ByteArrayContent(file), propertyInfo.Name, genericFileName);
}else
formContent.Add(getFileContent(value), propertyInfo.Name, genericFileName);
}
else if(value != null)
{
string output = value.ToString();
if (!String.IsNullOrEmpty(output))
{
formContent.Add(new StringContent(output), propertyInfo.Name);
}
}
}
return formContent;
}
private HttpContent getFileContent(object obj)
{
if (obj is Stream stream)
{
return new StreamContent(stream);
} else if (obj is byte[] byteArray)
{
return new ByteArrayContent(byteArray);
}
else
{
throw new Exception("Type not valid to create a HttpContent of file");
}
}
}
Veja que este código suporta Stream, byte[] e até mesmo uma lista destes tipos, como parâmetro de arquivo. Observe também que o foreach busca properties, este código não faz a conversão de fields.
O código abaixo mostra um exemplo de como utilizar.
class Program
{
private static string _rootUrl = "http://localhost:8080/tests/formdata";
public class ObjectForm
{
public string Param { get; set; }
public List<Stream> File { get; set; }
public ObjectForm()
{
File = new List<Stream>();
}
}
static void Main(string[] args)
{
var client = new HttpClient();
var obj = new ObjectForm();
obj.Param = "String Param";
obj.File.Add(new FileStream("Files/File1.txt", FileMode.Open, FileAccess.Read));
obj.File.Add(new FileStream("Files/File2.json", FileMode.Open, FileAccess.Read));
MultipartFormDataContent formdata = new MultipartFormDataContentParser<ObjectForm>(obj).Parse();
HttpResponseMessage response = client.PostAsync(_rootUrl, formdata).Result;
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}
}
Top comments (1)
Muito bom. Parabéns.