A single-project .NET 10 Blazor Server application that summarizes uploaded documents with Claude Sonnet 5 on Amazon Bedrock, storing results in SQL Server.
- 🤖 AI Summaries: Amazon Bedrock Converse API with Claude Sonnet 5
- 📄 Text Extraction: PDF text extraction via PdfPig, plus plain-text and log files
- 📤 Upload: Drag-and-drop or file picker, with size and file-type validation
- 🗂️ Document List: Newest first, with upload timestamp, status, and summary preview
- 💾 SQL Server: Entity Framework Core 10, with a local instance in Docker
- 🔐 Credentials: Optional AWS Secrets Manager lookup for RDS credentials
- 🧭 Provider Indicator: Header pill reports the database engine actually in use
One ASP.NET Core project. Interactive Server components render the UI; a small pipeline handles storage, extraction, and summarization.
src/DocumentProcessor.Web/
├── Components/
│ ├── Documents/ # DocumentList, DocumentUploader, StatusBadge
│ ├── Layout/ # MainLayout, DatabaseIndicator, DatabaseFooter
│ ├── Pages/ # Home, Error
│ └── Shared/ # ModalDialog
├── Configuration/ # BedrockOptions, StorageOptions, DatabaseOptions
├── Data/ # AppDbContext, connection resolution
├── Extensions/ # DI registration
├── Models/ # Document, DocumentStatus, Notification
├── Services/ # Storage, text extraction, summarization, pipeline
└── wwwroot/ # app.css, Bootstrap
Upload flow:
Browser → Home.SaveAsync → IDocumentStorage (disk)
→ AppDbContext (row, status Pending)
→ DocumentPipeline → DocumentTextExtractor (PdfPig)
→ IDocumentSummarizer (Bedrock Converse)
→ AppDbContext (summary, status Processed)
- .NET 10.0 SDK
- Docker (for local SQL Server) or an existing SQL Server instance
- An AWS account with Bedrock access to Claude Sonnet 5 in your chosen region
- AWS credentials available to the default SDK chain
-
Clone the repository
git clone https://github.com/aws-samples/sample-document-processing-system.git cd sample-document-processing-system -
Configure AWS credentials
aws configure
Or export
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY, andAWS_DEFAULT_REGION.Confirm the model is reachable:
aws bedrock-runtime converse \ --region us-east-1 \ --model-id global.anthropic.claude-sonnet-5 \ --messages '[{"role":"user","content":[{"text":"Reply with: OK"}]}]' \ --inference-config '{"maxTokens":20}'
-
Start SQL Server
docker compose up -d
Runs
mcr.microsoft.com/mssql/server:2022-lateston port 1433 with thesapasswordLocalDev!Passw0rd, matching the default connection string. Override it by settingMSSQL_SA_PASSWORDbeforedocker compose upand updating the connection string to match. Data persists in thesqlserver-datavolume. -
Run the application
cd src/DocumentProcessor.Web dotnet runThe
DPSdatabase andDocumentstable are created on first run. -
Open the app
Navigate to https://localhost:7266. The HTTP port redirects there.
- Drag files onto the drop zone or click Browse files
.pdf,.txt, and.logare accepted, up to 50 MB and 10 files per upload- Rejected files report why, inline
- Each document is saved to disk, recorded, then summarized
Uploads are processed synchronously, so the request stays open until Bedrock responds.
- Ordered by upload time, newest first
- Shows file type, name, status, upload timestamp, and a two-line summary preview
- The eye button opens the full summary; it is disabled until one exists
- Delete is a soft delete, so rows stay in the table behind a global query filter
- Backend: .NET 10, ASP.NET Core Blazor Server (Interactive Server), EF Core 10
- Database: Microsoft SQL Server (2022 in Docker for local development)
- AI: Amazon Bedrock Converse API, Claude Sonnet 5
- Documents: PdfPig 0.1.11
- Frontend: Bootstrap 5, Bootstrap Icons, custom CSS
All settings live in src/DocumentProcessor.Web/appsettings.json and bind to option
classes validated at startup, so a bad value fails the build-up rather than the first
request.
"Bedrock": {
"Region": "us-east-1",
"SummarizationModelId": "global.anthropic.claude-sonnet-5",
"MaxTokens": 2000,
"MaxInputCharacters": 10000,
"MaxPdfPages": 5
}MaxPdfPages and MaxInputCharacters bound how much text is sent per document.
Note: Claude Sonnet 5 rejects
temperatureandtopP. The inference config intentionally sets onlymaxTokens.
"Storage": {
"RootPath": "uploads",
"MaxFileSizeMegabytes": 50,
"MaxFilesPerUpload": 10,
"AllowedExtensions": [ ".pdf", ".txt", ".log" ]
}Files are written to uploads/yyyy/MM/dd/. Only extensions the extractor can read should
be listed here.
"ConnectionStrings": {
"DefaultConnection": "Server=localhost,1433;Database=DPS;User Id=sa;Password=LocalDev!Passw0rd;TrustServerCertificate=true;MultipleActiveResultSets=true"
},
"Database": {
"UseSecretsManager": false
}Set Database:UseSecretsManager to true to build the connection string from an AWS
Secrets Manager secret whose description starts with
Password for RDS MSSQL used for MAM319.:
{
"username": "your_username",
"password": "your_password",
"host": "your-db-host.rds.amazonaws.com",
"port": "1433",
"dbname": "your_database_name"
}If the lookup fails, the app logs a warning and falls back to DefaultConnection.
The app targets SQL Server today and is structured so the engine can change in one place.
DatabaseConnectionResolver.DetectProviderinfers the engine from the connection string (Host=/Username=means Npgsql;Server=/User Id=means SQL Server)DatabaseIndicatorand the footer report that provider, so a successful migration is visible in the UI rather than assumedServiceCollectionExtensions.AddDocumentProcessinghas the single provider switch and currently throws a clear error for PostgreSQL instead of passing Npgsql syntax toSqlClient
To complete a migration:
- Add
Npgsql.EntityFrameworkCore.PostgreSQL - Add the
DatabaseProvider.PostgreSqlarm callingUseNpgsql - Point
DefaultConnectionat the Aurora cluster
The entity configuration uses no SQL-Server-specific types, so the mapping ports unchanged.
| Status | Meaning |
|---|---|
Pending |
Row created, not yet processed |
Processing |
Text extraction and summarization under way |
Processed |
Summary stored |
Failed |
Extraction or the Bedrock call threw; see logs |
- The
sapassword inappsettings.jsonexists only for the throwaway local container. Use Secrets Manager, environment variables, or user-secrets for anything real. - Uploaded files are stored on local disk under
uploads/, which is git-ignored. - There is no authentication; add it before exposing the app.
- Database: RDS for SQL Server, or Aurora PostgreSQL after the migration above
- Compute: ECS, EC2, or Elastic Beanstalk
- Credentials: Secrets Manager with
Database:UseSecretsManagerenabled - Schema:
EnsureCreatedAsync()creates the schema on first run but cannot evolve it. Adopt EF Core migrations before running more than one environment.
docker-compose.yml provisions SQL Server for development only; the app itself runs on the
host via dotnet run. Containerizing it needs a standard .NET 10 Dockerfile.
The installed ASP.NET Core runtime does not match the target framework. Install the .NET 10
runtime, or check dotnet --list-runtimes.
Framework assets resolve through the static-web-assets manifest, which loads in the
Development environment. Ensure ASPNETCORE_ENVIRONMENT=Development when running
dotnet run; a published build serves them from wwwroot.
docker compose ps— is the container healthy?- Confirm port 1433 is free and the password matches the connection string
- With
UseSecretsManagerenabled, check the warning logged at startup
- Confirm model access is granted for Claude Sonnet 5 in the configured region
aws bedrock list-inference-profiles— isglobal.anthropic.claude-sonnet-5active?AccessDeniedExceptionmeans the caller lacksbedrock:InvokeModel- A
temperature/topPvalidation error means sampling parameters were reintroduced
- Only
.pdf,.txt, and.logare accepted; others are rejected at selection - Files over
MaxFileSizeMegabytesare rejected - A
Failedstatus means extraction or the Bedrock call threw — check the logs - Scanned PDFs with no text layer yield little for the model to summarize
- EF Core migrations in place of
EnsureCreatedAsync - Aurora PostgreSQL support
- Background processing so uploads return immediately
- Additional formats (DOCX, XLSX, images via OCR)
- Document classification persisted to a
Categorycolumn - Search, filtering, and pagination
- Authentication
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License.
- Built with .NET 10
- AI powered by Amazon Bedrock
- UI framework by Bootstrap
- PDF processing by PdfPig
Built with ❤️ using .NET 10 and Claude Sonnet 5 on Amazon Bedrock

