Use a browser FormData request with multipart/form-data, then bind the matching form field to an ASP.NET Core IFormFile. The browser sends the PDF bytes; the API validates the upload and saves it under a server-generated name. The example below uses buffered binding for modest files and shows where deployment limits and storage decisions matter.
How the upload works
The browser sends a POST request containing a multipart form field. The field name must match the API parameter or model property: in this example, both use file. ASP.NET Core binds that part to an IFormFile, which the endpoint copies to a controlled storage location.
- The user chooses a PDF in a React file input.
- React appends the selected
FiletoFormDataunder the keyfile. fetchsends the form to the API. Do not set the request’sContent-Typeyourself; the browser must add the multipart boundary.- The API enforces its own size and content checks, then saves the upload and returns an application-controlled identifier.
This is a file upload, not a JSON upload: do not stringify the form or convert the PDF to base64 for the ordinary multipart route.
Build the React upload form
This component keeps the selected file in the native input, disables repeat submissions while a request is in progress, and checks the HTTP response before reporting success. Replace /api/files with the API origin or route used by your application.
#1 Best Overall
- PORTABLE SCANNER FOR USE ON-THE-GO — The fastest and lightest mobile single-sheet-fed compact document scanner in its class¹
- QUICK DOCUMENT SCANNING ― This Epson ultra-fast scanner scans a single page as quickly as 5.5 seconds²; Windows and Mac compatible
- VERSATILE PAPER HANDLING ― Portable scanner scans documents up to 8.5 x 72 in; Also easily digitizes receipts and ID cards to make accounting, bookkeeping, and organizing simpler
- INTUITIVE, HIGH-SPEED SOFTWARE — Epson ScanSmart Software³ is a smart tool allowing you to easily scan, review, and save; Stay organized easily with the help of this Epson scanner
- EASY SETUP — USB-powered connect to your computer for quick and simple scanning; No batteries or external power supply required to operate portable document scanner; Standard Connectivity: USB 2.0
import { useState } from "react";
export default function PdfUpload() {
const [status, setStatus] = useState("");
const [busy, setBusy] = useState(false);
async function handleSubmit(event) {
event.preventDefault();
const form = event.currentTarget;
const file = form.elements.namedItem("file").files[0];
if (!file) {
setStatus("Choose a PDF first.");
return;
}
const data = new FormData();
data.append("file", file);
setBusy(true);
setStatus("Uploading…");
try {
const response = await fetch("/api/files", {
method: "POST",
body: data
});
const result = await response.json().catch(() => ({}));
if (!response.ok) {
throw new Error(result.error || `Upload failed (${response.status}).`);
}
setStatus(`Uploaded. File ID: ${result.id}`);
form.reset();
} catch (error) {
setStatus(error.message || "Upload failed.");
} finally {
setBusy(false);
}
}
return (
<form onSubmit={handleSubmit}>
<label htmlFor="pdf-file">Choose a PDF</label>
<input
id="pdf-file"
name="file"
type="file"
accept="application/pdf,.pdf"
required
/>
<button type="submit" disabled={busy}>
{busy ? "Uploading…" : "Upload PDF"}
</button>
<p role="status" aria-live="polite">{status}</p>
</form>
);
}
The accept value helps filter the file chooser, but it is only a convenience for the user. It is not a security check: callers can bypass the browser and submit a different file directly.
Receive and safely store the file in ASP.NET Core
This minimal API example targets ASP.NET Core 10.0 and uses the default buffered IFormFile model binding path. It sets an application-specific 10 MiB limit; choose a limit that fits your product rather than treating this sample value as a framework recommendation. The example validates a PDF extension, declared media type, and PDF signature marker, generates a random storage name, and writes outside the web application directory. These checks are useful filters, not a substitute for full format validation or malware scanning.
using Microsoft.AspNetCore.Http.Features;
var builder = WebApplication.CreateBuilder(args);
const long MaxPdfBytes = 10 * 1024 * 1024;
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.MaxRequestBodySize = MaxPdfBytes + 1024 * 1024;
});
builder.Services.Configure<FormOptions>(options =>
{
options.MultipartBodyLengthLimit = MaxPdfBytes + 1024 * 1024;
});
var app = builder.Build();
var uploadRoot = Path.Combine(Path.GetTempPath(), "pdf-upload-store");
Directory.CreateDirectory(uploadRoot);
app.MapPost("/api/files", async (IFormFile file, CancellationToken cancellationToken) =>
{
if (file is null || file.Length == 0)
return Results.BadRequest(new { error = "Choose a non-empty PDF." });
if (file.Length > MaxPdfBytes)
return Results.Problem(statusCode: StatusCodes.Status413PayloadTooLarge,
title: "PDF exceeds the 10 MiB upload limit.");
var extension = Path.GetExtension(file.FileName);
if (!string.Equals(extension, ".pdf", StringComparison.OrdinalIgnoreCase) ||
!string.Equals(file.ContentType, "application/pdf", StringComparison.OrdinalIgnoreCase))
return Results.BadRequest(new { error = "Upload a PDF file." });
var prefix = new byte[5];
await using (var input = file.OpenReadStream())
{
var read = await input.ReadAsync(prefix.AsMemory(), cancellationToken);
if (read != prefix.Length || !prefix.AsSpan().SequenceEqual("%PDF-"u8))
return Results.BadRequest(new { error = "The file does not appear to be a PDF." });
}
var id = Guid.NewGuid().ToString("N");
var storagePath = Path.Combine(uploadRoot, id + ".pdf");
await using (var output = new FileStream(storagePath, FileMode.CreateNew,
FileAccess.Write, FileShare.None, 81920, useAsync: true))
await using (var input = file.OpenReadStream())
{
await input.CopyToAsync(output, cancellationToken);
}
return Results.Created($"/api/files/{id}", new { id });
});
app.Run();
The React field is named file, matching the endpoint parameter. If you rename one side, rename the other. The file name supplied by a caller is untrusted; this example does not use it as a path. Its generated identifier is the only storage name returned to the client. The sample’s temporary-directory location is illustrative: configure a dedicated persistent storage location for production, outside the application tree, with execute permission disabled and least-privilege access.
Rank #2
- FAST DOCUMENT SCANNING — Document scanner with feeder allows you to speed through stacks with a 50-sheet Auto Document Feeder (ADF); Efficient office scanner to help you scan more productively
- INTUITIVE, HIGH-SPEED SOFTWARE — Quickly scan with this desktop document scanner; Epson ScanSmart Software lets you easily preview scans, email files, upload to the cloud, and more; Plus, automatic file naming saves even more time
- SEAMLESS INTEGRATION — Easily incorporate your data into most document management software with the included TWAIN driver; Office document scanner integrates seamlessly with business workflows
- EASY SHARING — Duplex scanner allows you to scan straight to email or popular cloud storage2 services like Dropbox, Evernote, Google Drive, and OneDrive for simple storage and sharing
- SIMPLE FILE MANAGEMENT — Scanner allows the creation of searchable PDFs with Optical Character Recognition (OCR) and convert scans to editable Word or Excel files effortlessly; Designed for home and office document scanning
The small signature check reads the first five bytes and confirms the PDF marker. A malicious or malformed file can still pass that check. Validate content for your threat model and scan uploads before making them available. Avoid returning physical file paths or rendering an untrusted original file name as HTML.
Set limits for the complete deployment
The ASP.NET Core 10.0 upload guidance documents a default 128 MB MultipartBodyLengthLimit for buffered form files and a 64 KB in-memory buffering threshold before buffering moves to a temporary disk file. Those are framework defaults, not safe application limits or a guarantee that a request of that size will reach your endpoint. Hosting server, reverse proxy, gateway, and application settings may each impose a lower cap.
Set a deliberate maximum at the application level and check the corresponding limits at every layer in the deployed path. Make the API’s error response useful to the client, and ensure temporary storage has room for concurrent uploads. For example, a 10 MiB per-file cap is not a promise that ten simultaneous requests need only 10 MiB of storage: buffering and temporary files can multiply resource use.
Rank #3
- OUR MOST ADVANCED SCANSNAP. Large touchscreen, fast 45ppm double-sided scanning, 100-sheet document feeder, Wi-Fi and USB connectivity, automatic optimizations, and support for cloud services. Upgraded replacement for the discontinued iX1600
- CUSTOMIZABLE. SHARABLE. Select personalized profiles from the touchscreen. Send to PC, Mac, mobile devices, and clouds. QUICK MENU lets you quickly scan-drag-drop to your favorite computer apps
- STABLE WIRELESS OR USB CONNECTION. Built-in Wi-Fi 6 for the fastest and most secure scanning. Connect to smart devices or cloud services without a computer. USB-C connection also available
- PHOTO AND DOCUMENT ORGANIZATION MADE EFFORTLESS. Easily manage, edit, and use scanned data from documents, receipts, photos, and business cards. Automatically optimize, name, and sort files
- AVOIDS PAPER JAMS AND DAMAGE. Features a brake roller system to feed paper smoothly, a multi-feed sensor that detects pages stuck together, and skew detection to prevent paper damage and data loss
Choose buffering, streaming, and storage deliberately
Buffered binding with IFormFile
Use the example’s simpler binding approach when the allowed PDFs are modest and request concurrency is manageable. ASP.NET Core buffers the multipart file before endpoint processing, using memory up to its configured threshold and temporary disk beyond it. Large files or many concurrent uploads can increase memory, disk, and cleanup pressure.
Streaming multipart data
For large files or workloads where buffering strains memory or temporary storage, implement explicit multipart streaming and process sections as they arrive. Streaming can reduce buffering pressure, but it adds parsing, validation, cleanup, and error-handling work; it does not by itself promise a faster upload. Pass cancellation through reads and writes so disconnected or cancelled requests do not keep consuming resources. Configure and test request limits for the streaming route as well.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Pick storage for retrieval and operations
| Storage choice | When it can fit | Trade-offs to assess |
|---|---|---|
| Database | Small files that are naturally retrieved with related records. | Consider database growth, backup and retrieval patterns, and operational cost. |
| Filesystem or network share | Larger files or applications already built around file storage. | Plan permissions, backups, durability, capacity, and how the API maps IDs to files. |
| Cloud data storage | Scalable or resilient storage needs and large storage scenarios. | Evaluate access control, durability and recovery needs, integration complexity, and cost. |
No storage option is universally best. Choose based on file sizes, access patterns, durability requirements, access control, expected scale, and the operational systems your team can maintain.
Rank #4
- Enjoy high speed scanning in as fast as 8 seconds, with the included USB Type-C cable. With USB Type-C the Cano scan lied 400 has one cable for data and power.
- Preserve detailed photos and images thanks to 4800 x 4800 dpi resolution, and with image enhancements, such as color restore and dust removal, Your photos will continue to look great.
- Enjoy ease of use with 'EZ' Buttons. With auto scan mode, the Scanner automatically detects what you are scanning; built-in PDF buttons, scan and save multi-page pdf's that are editable and searchable
- Paper size: 8.27 x 11.69, 8.50 x 11.69
Validate and protect uploads on the server
- Enforce a maximum size and reject empty files. Do not rely on the browser chooser or client-side checks.
- Allow only the file types your feature needs, then validate server-side. The submitted extension and
Content-Typeare both user-controlled and do not prove the bytes are a valid PDF. - Use server-generated storage names. Treat the original name as untrusted display text; remove path information and HTML-encode it if you show or log it.
- Keep uploads outside the application directory, disable execution in the upload location, and restrict filesystem permissions.
- Consider malware scanning before making a file downloadable or otherwise available to users.
- Handle cancellation, malformed multipart bodies, storage failures, and full disks. Return clear status codes without exposing internal paths or exception details.
- If the API uses cookie authentication and cross-site request risks apply, configure and send the appropriate antiforgery token for that endpoint design.
Handle cross-origin requests and upload feedback
If the React page and API have different origins, configure the API’s CORS policy to allow the page’s origin and the required method and headers. CORS is not authentication and does not make an endpoint private. For cookie-based authentication, credentials and antiforgery protection require deliberate configuration on both sides; do not enable broad origins with credentials.
The sample reports a final success or error, not byte-by-byte progress. The standard fetch example is adequate when a final status is enough. If the interface must show upload progress, use an upload mechanism that exposes progress events or a resumable-upload design, and define how interrupted uploads are identified and cleaned up.
Troubleshoot common upload failures
- 400 response or missing file: Check that the client uses
data.append("file", file)and the server bindsIFormFile file. The multipart field names must match. - 415 Unsupported Media Type or binding errors: Send
FormDataas the request body. Do not JSON-serialize it or manually setContent-Type: multipart/form-data; that can omit the boundary the server needs. - 413 Payload Too Large: The request exceeds a limit in the API, web server, reverse proxy, or gateway. Identify which layer rejected it, then decide whether to raise that layer’s limit or lower the product’s accepted file size.
- Browser reports a network error: Check the API URL, TLS/connectivity, and CORS configuration for a cross-origin request. A CORS failure can prevent the page from reading the response even if the server received the request.
- Server returns 500 while saving: Check the configured storage location, write permissions, free space, and cancellation or I/O errors. Log operational details securely, but do not expose filesystem paths in the public response.
- Chooser rejects or filters the desired file: Adjust the user-interface
accepthint if appropriate. Keep the server validation authoritative; changing the chooser does not change what requests the API must defend against.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server, not a PDF-upload endpoint. It can be useful alongside this workflow if you also need a clean screenshot of a page—for example, to capture an upload confirmation screen—but it does not send the selected PDF to your ASP.NET Core API. Its request returns a screenshot or PDF of a web page, and the service’s stated clean-shot handling removes cookie banners, popups, and chat widgets before capture; bot checks, blank pages, and failed loads are not billed. It also offers an MCP server for AI agents and includes 1,000 screenshots a month free without a card, with paid plans starting at $5 for 3,000.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for request options. If you want to add page screenshots as a separate part of your workflow, sign up for the free plan.
Best Value
- FAST SPEED AND DUPLEX SCANNING – Scan single and double-sided documents in a single pass at up to 16 ppm(1). Color scanning doesn’t slow you down at all as it has the same scan speed as black and white document scanning.
- ULTRA COMPACT – At less than 1 foot in length you can fit this device virtually anywhere (a bag, a purse, a pocket). The DSD (Desk Saving Design) feature reduces the amount of space needed to use the device, saving you 11 inches of desk space. (2)
- READY WHENEVER YOU ARE – The DS-740D is powered via an included micro USB 3. 0 cable allowing you to use it even where there is no outlet available. Plug it into you PC or laptop and you are ready to scan.
- WORKS YOUR WAY – Use the Brother free iPrint&Scan desktop app for scanning to multiple “Scan-to” destinations like PC, Network, cloud services, Email and OCR. (2) Supports Windows, Mac and Linux and TWAIN/WIA for PC/ICA for Mac/SANE drivers. (3)
- OPTIMIZE IMAGES AND TEXT – Automatic color detection/adjustment, image rotation (PC only), bleed through prevention/background removal, text enhancement, color drop to enhance scans. Software suite includes document management and OCR software. (4)
Frequently Asked Questions
Does the React `accept` attribute ensure that only PDFs can be uploaded?
No. It only guides the file chooser; validate the upload on the server.
Can I upload several PDFs in one request?
The example handles one file. For multiple files, design both the client form fields and endpoint binding for a collection, then validate and limit each file and the request as a whole.
Is ScreenshotNeo a way to send my PDF to the API?
No. ScreenshotNeo captures web pages; it does not upload the selected PDF to your ASP.NET Core endpoint.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




