C# File Upload
Upload Files from C# Using HttpClient (No NuGet Vendor SDK)
Upload files from C# with HttpClient. No SDK, REST API, CDN delivery, prepaid credits.
If you build on ASP.NET Core, a Worker Service, a Blazor server app, or .NET MAUI, you already have the only HTTP client you need: HttpClient. Uploading a file to files.link is three awaited calls, no AWSSDK.S3 NuGet package, no credential provider chain, no IAM policy JSON. That keeps your published assembly lean — the AWS SDK alone adds several megabytes and a config surface most apps never touch.
The pattern is the same three steps you would use from any language, expressed idiomatically with IHttpClientFactory and StreamContent so large files never sit fully in managed memory. Step one POSTs metadata to /v1/files/{folderId} with the raw API key in the Authorization header (no Bearer prefix) and reads the presigned url and id out of the urls array. Step two PUTs the file stream to that URL. Step three POSTs the id list to /v1/files/confirm-upload.
record Slot(string url, string id);
record UploadResponse(bool success, Slot[] urls);
public async Task<string> Upload(HttpClient http, string folderId, string path)
{
var key = Environment.GetEnvironmentVariable("FILESLINK_KEY");
var meta = new { filesMetadata = new[] { new { name = Path.GetFileName(path), size = new FileInfo(path).Length, type = "image/png" } } };
// Authorization is scoped per-request so it is NEVER sent to the presigned URL.
var create = new HttpRequestMessage(HttpMethod.Post, $"https://api.files.link/v1/files/{folderId}") { Content = JsonContent.Create(meta) };
create.Headers.Add("Authorization", key);
var r1 = await http.SendAsync(create);
var slot = (await r1.Content.ReadFromJsonAsync<UploadResponse>())!.urls[0];
await using var fs = File.OpenRead(path);
var put = new StreamContent(fs);
put.Headers.ContentType = new MediaTypeHeaderValue("image/png"); // must match the type sent in create
await http.PutAsync(slot.url, put); // presigned URL — no Authorization header
var confirm = new HttpRequestMessage(HttpMethod.Post, "https://api.files.link/v1/files/confirm-upload") { Content = JsonContent.Create(new { ids = new[] { slot.id } }) };
confirm.Headers.Add("Authorization", key);
await http.SendAsync(confirm);
return slot.id;
}Register the client with services.AddHttpClient() so connection pooling and DNS refresh are handled for you, and keep the API key in user-secrets during development and Azure Key Vault or environment variables in production. Because files.link returns a CDN-backed URL per file, you can hand that URL straight to a Blazor component, an MVC view, or a MAUI Image control.
Visibility is per file: public files resolve directly over the global CDN, private files are issued short-lived signed URLs. Storage is encrypted at rest and metered against prepaid credits — no metered egress invoice waiting at month end.
Benefits With No Complexity
Global CDN delivery
Edge-cached worldwide
Signed-URL security
What You Get
Unlimited files
Unlimited storage
Public + Private storage
CDN ready links
Prepaid credits
More coming soon
How files.link Works
1. Upload
2. Copy
3. Use Anywhere
Why Developers Choose files.link
A Better Way to Store & Deliver Files
| AWS S3 (AWSSDK.S3) | Azure Blob (Azure.Storage.Blobs) | files.link | |
|---|---|---|---|
| Works with built-in HttpClient (no vendor NuGet) | |||
| Streams from disk via StreamContent | |||
| Global CDN delivery on every file | |||
| No credential provider chain to configure | |||
| Prepaid credits (no surprise bills) |
Calculate Your Needs
Storage
Egress
CDN Bandwidth
Upload Files from C#
- Global CDN delivery
- Edge-cached worldwide
- Signed-URL security
- Unlimited files
- Unlimited storage
- Public + Private storage
- No subscription — prepaid credits keep spend predictable