0

I'm not being able to post multipart (for file upload) plus raw (for json object) in the same request in Postman.

I have a web api .Net Framework (NOT Core) endpoint to upload a file like the next:

[Route("UploadVideo")]
[HttpPost]
public async Task<HttpResponseMessage> UploadVideo(FileUpload fileUpload)
{
    string videoAllowedExtensions = ConfigurationManager.AppSettings.Get("VideoAllowedExtensions");
    int.TryParse(ConfigurationManager.AppSettings.Get("FileMaxSize"), out int fileMaxSize);

    fileUpload .AllowedExtensions = videoAllowedExtensions;
    fileUpload .MaxSize = fileMaxSize;

    if (fileUpload != null) 
    {
        return await UploadFile(fileUpload);
    }

    return Request.CreateResponse(HttpStatusCode.BadRequest, "No File Attached");
}

public async Task<HttpResponseMessage> UploadFile(FileUpload fileUpload)
{
    Dictionary<short, Tuple<short, string>> filesUploadStatus = new Dictionary<short, Tuple<short, string>>();
    Tuple<short, string> fileUploadStatus;
    short key = 0;
    var httpRequest = HttpContext.Current.Request;
    foreach (string file in httpRequest.Files)
    {
        var postedFile = httpRequest.Files[file];
        if (postedFile != null && postedFile.ContentLength > 0)
        {
            UploadFile uploadFile = new UploadFile
            {
                FileName = postedFile.FileName,
                ContentLength = postedFile.ContentLength,
                ContentType = postedFile.ContentType,
                InputStream = postedFile.InputStream,
                EnterpriseId = fileUpload.EnterpriseId,
                AllowedExtensions = fileUpload.AllowedExtensions,
                MaxSize = fileUpload.MaxSize,
                AzureFolder = fileUpload.AzureFolder
            };
            fileUploadStatus = await CatalogueService.UploadFile(uploadFile);
        }
        else
        {
            var responseMessage = string.Format("Please, upload a file.");
            fileUploadStatus = new Tuple<short, string>((short)ConstantsADM.ResponseStatus.BadRequest, responseMessage);
        }

        filesUploadStatus.Add(key, fileUploadStatus);
        key++;
    }

    HttpStatusCode httpStatudCode = GetStatusCode(filesUploadStatus);

    return Request.CreateResponse(httpStatudCode, filesUploadStatus);
}

private HttpStatusCode GetStatusCode(Dictionary<short, Tuple<short, string>> filesUploadStatus) 
{
    HttpStatusCode response = HttpStatusCode.BadRequest;

    foreach (var dic in filesUploadStatus) 
    {
        short httpResponse = dic.Value.Item1;
        switch (httpResponse)
        {
            case (short)ConstantsADM.ResponseStatus.Created:
                response = HttpStatusCode.Created;
                break;
            case (short)ConstantsADM.ResponseStatus.NotFound:
                response = HttpStatusCode.NotFound;
                break;
        }
    }

    return response;
}

public async Task<Tuple<short, string>> UploadFile(UploadFile uploadFile)
{
    string responseMessage;

    CloudStorageAccount storageAccount = AzureHelper.Connect(uploadFile.EnterpriseId);
    if (storageAccount!=null)
    {
        try
        {
            Tuple<short, string> tup;
            CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();

            var shortEnv = ConfigurationManager.AppSettings.Get("AzureStorageContainer");
            var environment = EnvironmentHelpers.GetEnvironment(shortEnv);

            CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference(string.Format("{0}{1}", uploadFile.AzureFolder, environment));

            await cloudBlobContainer.CreateIfNotExistsAsync();//TODO: Don't create
            BlobContainerPermissions permissions = new BlobContainerPermissions
            {
                PublicAccess = BlobContainerPublicAccessType.Blob
            };
            await cloudBlobContainer.SetPermissionsAsync(permissions);

            string ext = System.IO.Path.GetExtension(uploadFile.FileName);
            Guid oGUID = Guid.NewGuid();
            string imageName = uploadFile.EnterpriseId.ToString() + "_" + oGUID.ToString() + ext;

            if (uploadFile != null && uploadFile.ContentLength > 0)
            {
                IList<string> AllowedFileExtensions = uploadFile.AllowedExtensions.Split(',');

                var extension = ext.ToLower();
                if (!AllowedFileExtensions.Contains(extension))
                {
                    responseMessage = string.Format("Please Upload file of type {0}", uploadFile.AllowedExtensions);
                    return new Tuple<short, string>((short)ConstantsADM.ResponseStatus.BadRequest, responseMessage);
                }
                else if (uploadFile.ContentLength > uploadFile.MaxSize) // 2048 * 2048 * 1; //Size = 2 MB
                {
                    responseMessage = string.Format("Please Upload a file upto {0} bytes.", uploadFile.MaxSize);
                    return new Tuple<short, string>((short)ConstantsADM.ResponseStatus.BadRequest, responseMessage);
                }
                else
                {
                    CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference(imageName);
                    cloudBlockBlob.Properties.ContentType = uploadFile.ContentType;
                    await cloudBlockBlob.UploadFromStreamAsync(uploadFile.InputStream);
                }

                responseMessage = string.Format("Image Updated Successfully.");
                return new Tuple<short, string>((short)ConstantsADM.ResponseStatus.Created, responseMessage);
            }
            responseMessage = string.Format("Please Upload an image.");
            tup = new Tuple<short, string>((short)ConstantsADM.ResponseStatus.NotFound, responseMessage);
            return tup;
        }
        catch (Exception ex)
        {
            responseMessage = ex.InnerException.ToString();
            return new Tuple<short, string>((short)ConstantsADM.ResponseStatus.BadRequest, responseMessage);
        }
    }
    else
    {
        responseMessage = string.Format("Connection was not successful.");
        return new Tuple<short, string>((short)ConstantsADM.ResponseStatus.NotFound, responseMessage);
    }
}

public class FileUpload
{
    public string FileTitle { get; set; }
    public string Description { get; set; }
    public short EnterpriseId { get; set; }
    public int UserId { get; set; }
    public int ApplicationId { get; set; }
    public string AzureFolder { get; set; }
    public string AllowedExtensions { get; set; }
    public int MaxSize { get; set; }
}

OK, this next way is NOT working as fileUpload is received as null or file is received as null depending if I hit SEND from Raw, or from form-data tabs.

[Route("UploadVideo")]
[HttpPost]
public async Task<HttpResponseMessage> UploadVideo(FileUpload fileUpload)
{
    string videoAllowedExtensions = ConfigurationManager.AppSettings.Get("VideoAllowedExtensions");
    int.TryParse(ConfigurationManager.AppSettings.Get("FileMaxSize"), out int fileMaxSize);

    fileUpload .AllowedExtensions = videoAllowedExtensions;
    fileUpload .MaxSize = fileMaxSize;

    if (fileUpload != null) 
    {
        return await UploadFile(fileUpload);
    }

    return Request.CreateResponse(HttpStatusCode.BadRequest, "No File Attached");
}

File Upload button in form-data Jsoin object in Raw

But this next way it does work as it receives all parameters and the streamed file:

[Route("UploadVideo")]
[HttpPost]
public async Task<HttpResponseMessage> UploadVideo([FromUri] string fileTitle, [FromUri] string description,
                                [FromUri] short enterpriseId, [FromUri] int userId, 
                                [FromUri] int applicationId, [FromUri] string azureFolder) 
{
    string videoAllowedExtensions = ConfigurationManager.AppSettings.Get("VideoAllowedExtensions");
    int.TryParse(ConfigurationManager.AppSettings.Get("FileMaxSize"), out int fileMaxSize);

    FileUpload fileUpload = new FileUpload 
    {
        FileTitle = fileTitle,
        Description = description,
        EnterpriseId = enterpriseId,
        UserId = userId,
        ApplicationId = applicationId,
        AzureFolder = azureFolder,
        AllowedExtensions = videoAllowedExtensions,
        MaxSize = fileMaxSize
    };

    if (fileUpload != null) 
    {
        return await UploadFile(fileUpload);
    }

    return Request.CreateResponse(HttpStatusCode.BadRequest, "No File Attached");
}

The upload button in form-data The query params

WebApi.config.cs

...
config.Formatters.XmlFormatter.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("multipart/form-data"));
...

I'm expecting to be able to do the request the common -and pretty- way for a post, I mean, receiving a json that will be autommatically mapped to my object.

Diego Perez
  • 2,188
  • 2
  • 30
  • 58
  • Is [this](https://stackoverflow.com/a/46344854/1734655) what you're looking for? – Ruslan Gilmutdinov Mar 31 '22 at 10:58
  • Thanks for your reply @Ruslan Gilmutdinov. This is certainly what I'm looking for, but in the link you provided all the examples are done for DotNet Core, and my Web Api is a .Net Framework one, and they suggest to use IFormFile, that is a .Net Core object and requires to install .Net Core libraries (and I don't know if they will like that here at my company). If possible (I'm starting to doubt that) I should be able to do it in a .Net Framework way. – Diego Perez Mar 31 '22 at 15:15
  • I doubt there is any convenient way in .Net Framework to automatically bind JSON in `multipart/form-data` to an object. I would try to parse JSON manually with `JsonConvert.DeserializeObject(HttpContext.Current.Request.Form["data"])` and extract files from `HttpContext.Current.Request.Files` (as you already do). – Ruslan Gilmutdinov Mar 31 '22 at 17:07

0 Answers0