Search code examples
c#angularjsuploadform-data

Issue with form-data name


I have an angular application that is uploading files using my API. I have a bit of code that looks like this:

var url = __env.apiUrl + 'documents/' + containerName + '/' + reference;
var formData = new FormData();            
var request = {
    method: 'POST',
    url: url,
    data: formData,
    headers: {
        'Content-Type': undefined
    }
};

formData.append('file', file);
formData.append('metadata', JSON.stringify(metadata));

return $http(request).then(function (response) {
    SimpleCache.remove(__env.apiUrl + '/documents');
    listDirectiveService.refresh('document');
    ngNotify.set('Your document was created.');
}, notifications.handleError).finally(function () {                
    onComplete();
});

On my API side, the c# used to get the file looks like this:

if (!request.Content.IsMimeMultipartContent("form-data")) throw new HttpResponseException(request.CreateResponse(HttpStatusCode.UnsupportedMediaType));
Valiate(containerName, directoryName);

var filesReadToProvider = await request.Content.ReadAsMultipartAsync();

// We assume that the form data name is file and metadata respectively
var fileStream = filesReadToProvider.Contents.SingleOrDefault(m => m.Headers.ContentDisposition.Name.Equals("\"file\"", StringComparison.OrdinalIgnoreCase));
var metaDataStream = filesReadToProvider.Contents.SingleOrDefault(m => m.Headers.ContentDisposition.Name.Equals("\"metadata\"", StringComparison.OrdinalIgnoreCase));

if (fileStream == null) throw new ArgumentNullException(nameof(fileStream));
if (metaDataStream == null) throw new ArgumentNullException(nameof(metaDataStream));

This works, but the problem is the name of the ContentDisposition. If you notice, it looks for "file" instead of file. Does anyone know why it has the extra quotes?


Solution

  • I never found out why this was happening, so I just made my function like this:

    public async Task<string> CreateAsync(HttpRequestMessage request, string containerName, string directoryName, string existingUrl = "")
    {
        if (!request.Content.IsMimeMultipartContent("form-data")) throw new HttpResponseException(request.CreateResponse(HttpStatusCode.UnsupportedMediaType));
        Valiate(containerName, directoryName);
    
        var filesReadToProvider = await request.Content.ReadAsMultipartAsync();
    
        // We assume that the form data name is file and metadata respectively
        var fileStream = filesReadToProvider.Contents.SingleOrDefault(m => 
            m.Headers.ContentDisposition.Name.Equals("\"file\"", StringComparison.OrdinalIgnoreCase) ||
            m.Headers.ContentDisposition.Name.Equals("file", StringComparison.OrdinalIgnoreCase));
        var metaDataStream = filesReadToProvider.Contents.SingleOrDefault(m =>
            m.Headers.ContentDisposition.Name.Equals("\"metadata\"", StringComparison.OrdinalIgnoreCase) ||
            m.Headers.ContentDisposition.Name.Equals("metadata", StringComparison.OrdinalIgnoreCase));
    
        if (fileStream == null) throw new ArgumentNullException(nameof(fileStream));
        if (metaDataStream == null) throw new ArgumentNullException(nameof(metaDataStream));
    
        // Upload our file
        var fileBytes = await fileStream.ReadAsByteArrayAsync();
        var mediaType = fileStream.Headers.ContentType.MediaType;
        var friendlyFileName = fileStream.Headers.ContentDisposition.FileName.Replace("\"", string.Empty);
        var fileName = $"{Guid.NewGuid()}{Path.GetExtension(friendlyFileName)}";
        var directory = GetDirectory(containerName, directoryName);
        var fileUrl = await Upload(directory, fileName, mediaType, fileBytes);
    
        // Add our metadata
        var metadata = await GetMetadataFromMemoryStreamAsync(metaDataStream);
        metadata.Add("fileName", friendlyFileName);
        metadata.Add("directory", directoryName);
        metadata.Add("created", DateTime.UtcNow.ToString(CultureInfo.InvariantCulture));
        await AddFileMetaDataAsync(fileUrl, metadata);
    
        // Delete any existing file
        if (!string.IsNullOrEmpty(existingUrl) && fileUrl != existingUrl) await DeleteAsync(containerName, directoryName, existingUrl);
    
        return fileUrl;
    }
    

    Just to cover all bases. It isn't the best, but it should work fine.