Como converter Object para MultipartFormDataContent ASP.NET
Tags: dotnet, aspnet, stream, bytearray
Published: 2020-12-20 21:37:04

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.
```csharp
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.
```csharp
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);
    }
}
```