Solarion
Honorary Master
- Joined
- Nov 14, 2012
- Messages
- 28,059
- Reaction score
- 17,822
South Africa’s biggest forum. Discuss, discover, and connect with thousands of members.
So tell me junior, what is cheap compared to SQL Server? MySQL?????If you’re only using SQL Server (let’s be honest), which isn’t cheap then use it.
I’d let the SQL Server handle auditing if needed as it can clean it up and also provides flexibility in picking languages, frameworks etc.
"/api/files": {
"post": {
"tags": [
"Files"
],
"operationId": "Files_UploadFile",
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"File": {
"type": "string",
"format": "binary",
"nullable": true
}
}
}
}
}
},
"responses": {
"204": {
"description": ""
}
}
}
},
uploadFile: async(file: FileParameter | null | undefined, abortSignal?: AbortSignal | undefined) : Promise<void> => {
let url_ = "/api/files";
url_ = url_.replace(/[?&]$/, "");
const content_ = new FormData();
if (file !== null && file !== undefined)
content_.append("File", file.data, file.fileName ? file.fileName : "File");
let config_: AxiosRequestConfig = {
data: content_,
method: "POST",
url: url_,
headers: {
},
signal: abortSignal
};
const { data } = await axiosToUse.request(config_).catch(error => Promise.reject(handleError(error)));
return data as void;
},
export interface FileParameter {
data: any;
fileName: string;
}
// I am assuming that FileParameter's Data property is of type "byte[]"
await using var fileStream = formFile.OpenReadStream();
using var memoryStream = new MemoryStream();
await fileStream.CopyToAsync(memoryStream, cancellationToken);
var fileContent = memoryStream.ToArray();
var fileParameter = new FileParameter
{
Data = fileContent,
Filename = formFile.Filename
}
Oh dear lord files and memory streams......having flashbacks....like back in Nam.I assume you want to do this.
This is easy
- Upload File in your MVC app
- Then Use API Client To call another API, sending the IFormFile data to the API
C#:// I am assuming that FileParameter's Data property is of type "byte[]" await using var fileStream = formFile.OpenReadStream(); using var memoryStream = new MemoryStream(); await fileStream.CopyToAsync(memoryStream, cancellationToken); var fileContent = memoryStream.ToArray(); var fileParameter = new FileParameter { Data = fileContent, Filename = formFile.Filename }
Oh dear lord files and memory streams......having flashbacks....like back in Nam.
Not moaning about just been in the trenches with it. Keep in mind restrictions ( web request length etc ) and the size and impact to your api with uploading files. Also, if I remember correctly there is a hard/soft limit for basic file uploading to be around ~40ish Mb. You need/should implement segmented uploading or ideally uploading to a proper blob repo ( Azure Storage / Amazone S3 etc ) and linking so as not to cause hiccups/hangs on your apis, nor rack up extra processing unnecessarily.

Yeah , we do large video uploads like that. Setup api call, segmented upload to azure blob storage, post api call with storage result and background services then run for processing/transcoding etc. Low api overhead, highly scalable and resilient.100% both AWS and azure make this really easy with signed URLs.
View attachment 1441041
Quite easy to implement the above in .Net too @Solarion
Something to think about once you have a working solution. Depends where/how you host your application and what storage you have
what does your openAPI requestBody look like

"/api/databases/upload-clean-database": {
"post": {
"tags": [
"Database"
],
"summary": "Uploads a clean database",
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"ContentType": {
"type": "string"
},
"ContentDisposition": {
"type": "string"
},
"Headers": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"Length": {
"type": "integer",
"format": "int64"
},
"Name": {
"type": "string"
},
"FileName": {
"type": "string"
}
}
},
"encoding": {
"ContentType": {
"style": "form"
},
"ContentDisposition": {
"style": "form"
},
"Headers": {
"style": "form"
},
"Length": {
"style": "form"
},
"Name": {
"style": "form"
},
"FileName": {
"style": "form"
}
}
}
}
},
"responses": {
"200": {
"description": "Uploaded database successfully",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
},
"400": {
"description": "Failed to upload database",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
},

That is strange, but it shouldn’t really matter. Could just be a version difference.
What does the FileParameter look like?
What happens if you load this openapi spec into postman and call it from there?
That’s exactly it.@_kabal_ as a matter of interest, why does one need signed url? For Azure i use FileshareClient or BlobClient in the webapi backend and then write to that as a stream. Is it so that a client can write directly to storage as opposed to via webapi?
That is strange, but it shouldn’t really matter. Could just be a version difference.
What does the FileParameter look like?
What happens if you load this openapi spec into postman and call it from there?


Ok to get this to work I had to wrap IFormFile in a class. Either that or else deal with like 6 parameters on the Client side which I think represent or are supposed to represent an IFormFile object. Odd.
Client
View attachment 1441271
API Side
View attachment 1441273
View attachment 1441275
Noted on the effective use of resources. You don't want to bog down your resource by just moving bytes into storage. My largest file being uploaded is 60MB.. so prob not a huge issue.That’s exactly it.
It’s not a huge issue if you are on bare metal, and your users aren’t uploading large files - you basically have unlimited cpu + memory.
But imagine running with a 0.25 vCPUs and 512/1024MB memory (fargate/azure equivalent). You’ll potentially quickly
run into issues trying to handle multiple users/uploads.
Getting a signed URL is fast/cheap.
And S3/Azure equivalent bandwidth/scaling can be seen as practically “infinite”
You can also potentially avoid ingress -> egress -> ingress costs, which could realistically happen if users are uploading GB’s of files
It also essentially does the same for serving files. When a user wants to download a file, check if they are allowed to download that file, get a signed url, and return a 302 with the signed url.
The signed urls are also only valid for x amount of time




