How To Upload File With Form/Meta-Data To C# Server?

Hi all,

I have the following method in my C# server:

[HttpPost]
public async Task<IActionResult> UploadFile2(IFormFile file, int extra)
{
	string output = $"{file.FileName} - {file.Length} - {extra}";
	return Ok(output);
}

This method has always been capable of accepting extra data using my previous file uploader: Vue File Agent.

With Vue File Agent, this works:

return this.$refs.vueFileAgent.upload(this.uploadUrl, this.uploadHeaders, [fileRecord], (fileData) => {
	var formData = new FormData();
	formData.append(this.extraParam, this.extraParamValue);
	formData.append('file', fileData.file);
	return formData;
});

I am trying to get Uppy to do the same.

The docs say to have this setup:

var uppy = new Uppy();

uppy.use(XHRUpload, {
	endpoint: '/api/upload/UploadFile2',
	formData: true
});

uppy.on('file-added', (file) => {
	uppy.setFileMeta(file.id, {
		extra: 237
	});
});

The file successfully uploads. But the ‘int extra’ parameter remains 0.

I compared Vue File Agent’s successful request to Uppy’s request. They look very similar. Their multipart source is almost the same, except that Uppy adds a few extra by default (type, name and relativePath). Not sure why one is accepted and the other is not.

Also, when I change the parameter to ‘string extra’, Uppy’s upload fails altogether, saying: “The extra field is required.”.

It seems strange that Uppy’s behavior would change, based on which primitive type my extra form data field has.

This almost makes me think this requires a bug report.

Anyway, can somebody give me a pointer on how to configure Uppy so that my C# web method will accept both the file upload, as well as the extra info?

Thanks in advance!

Jay

Uppy Headers

Uppy Payload

Uppy Response

uppy-response

The outputted ‘extra’ parameter remains 0.

It all looks correct to me.

Does anybody see what might cause the problem of my backend not receiving the extra info?

The weird thing is, the Vue File Agent upload doesn’t show any image data in its successful upload request.

Not sure how this is possible, when a file is indeed successfully uploaded. I have visual confirmation of this on my production site.

This makes me feel like Vue File Agent’s request and Uppy’s request are, in fact, slightly different from each other.

Maybe it’s got something to do with the fact that I’m testing Vue File Agent on my production server, rather than localhost. Production is the only place I still have Vue File Agent running at all, anymore.

(Vue File Agent only supports Vue 2. I’m in the middle of migrating to Vue 3, so I no longer have a working Vue File Agent on localhost.)

Uppy runs on localhost, currently.

I’ve been comparing requests (Vue File Agent vs Uppy) using Fiddler.

The only difference I noticed, was the ‘accept’ header. It was set to ‘application/json’ in VFA’s request, but to ‘/’ in Uppy’s request.

I have since modified my Uppy code to set the header to ‘application/json’ as well.

Here’s the working VFA request on production:

POST https://contentbase.com/api/admin/UploadPackageImage HTTP/1.1
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,nl-NL;q=0.8,nl;q=0.7
Accept: application/json
Connection: keep-alive
Content-Length: 382990
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryou6nPHrBCr6xeb1M
Host: contentbase.com
Origin: https://contentbase.com
Referer: https://contentbase.com/admin/public-package/1247/
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-ch-ua: "Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36

------WebKitFormBoundaryou6nPHrBCr6xeb1M
Content-Disposition: form-data; name="idPackage"

1247
------WebKitFormBoundaryou6nPHrBCr6xeb1M
Content-Disposition: form-data; name="file"; filename="Template001.jpg"
Content-Type: image/jpeg

[image data edited out]

------WebKitFormBoundaryou6nPHrBCr6xeb1M--

Here’s the non-working Uppy request on localhost:

POST https://localhost:7006/api/upload/UploadFile2 HTTP/1.1
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,nl-NL;q=0.8,nl;q=0.7
accept: application/json
Connection: keep-alive
Content-Length: 383300
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarydCIiNLTeyTEwkI4h
Host: localhost:7006
Origin: https://localhost:7006
Referer: https://localhost:7006/
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-ch-ua: "Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36

------WebKitFormBoundarydCIiNLTeyTEwkI4h
Content-Disposition: form-data; name="relativePath"

null
------WebKitFormBoundarydCIiNLTeyTEwkI4h
Content-Disposition: form-data; name="name"

Template001.jpg
------WebKitFormBoundarydCIiNLTeyTEwkI4h
Content-Disposition: form-data; name="type"

image/jpeg
------WebKitFormBoundarydCIiNLTeyTEwkI4h
Content-Disposition: form-data; name="idPackage"

1247
------WebKitFormBoundarydCIiNLTeyTEwkI4h
Content-Disposition: form-data; name="file"; filename="Template001.jpg"
Content-Type: image/jpeg

[image data edited out]

------WebKitFormBoundarydCIiNLTeyTEwkI4h--

Save for the ‘type, name & relativePath’ multipart content that Uppy adds, the requests are identical.

(The only header that was edited out, was the cookie header. These are wildly different. But it can’t possibly cause the problem, anyway.)

So why won’t my server side method accept the additional idPackage parameter?

[HttpPost]
public async Task<IActionResult> UploadFile2(IFormFile file, int idPackage)
{
	string output = $"{file.FileName} - {file.Length} - {idPackage}";
	return Ok(output);
}

When I add ‘string type, string name, string relativePath’ to the method, in order to try to get it to match with the upload request, I get a bad request error.

Is there any way I can tell Uppy not to include name, type and relativePath in the generated request?

This is the only difference in requests. That’s got to be the cause.

Why can’t I just add type, name and relativePath to my upload method to make it work?

Any advice on making it work, no matter how, will be greatly appreciated.

I just found out that these very same requests do work in another project of mine.

It’s starting to look like some sort of server side setting, rather than an Uppy-related problem.

For this reason, I crossposted this on Stack Overflow.

I just solved this by using the [FromForm] attribute in front of my extra parameter.

[HttpPost]
public async Task<IActionResult> UploadFile2(IFormFile file, [FromForm]int idPackage)
{
    string output = $"{file.FileName} - {file.Length} - {idPackage}";
    return Ok(output);
}

Turns out it wasn’t an Uppy-problem at all.