Files, Reports, and Browser Boundaries
The import that read C:\Orders\in.csv
becomes Upload → configured storage root → importer → the reused business logic, Export to Excel becomes a managed
.xlsx + Application.Download, Print Invoice becomes a server PDF in a PdfViewer, and long reports go
through a process-wide report queue (progress, cancel, view, download) that every browser session sees.
Run it
cd "LearnWisej-Samples/From WinForms to the Web Course/Module 6/OrderDesk.Web"
dotnet run -f net10.0 --urls http://localhost:5606
Then open http://localhost:5606. (Visual Studio: open OrderDesk.slnx, F5.) No Office, no printer needed.
There is no login in this module: the first session of the process acts as kelly, every later one as sam
(Application.Session.User), so the queue's Owner column can show two users.
What to try
| Action | What you should see |
|---|---|
Upload order-batch.csv… → pick OrderDesk.Web/wwwroot/samples/order-batch.csv | order-batch.csv → 5 order(s) saved, 0 skipped, a toast, and orders 1043–1047 at the top of the invoice list (Tailspin Toys 5,652.50 after its 5 % discount). The file is stored under App_Data/uploads/ |
| Upload a non-.csv or a file over 1 MB | a warning toast; nothing is imported |
| Pick an order → Print Invoice (PDF) | the invoice PDF, built on the server, opens in a modal PdfViewer with a Download button |
| Export .xlsx ⬇ | the browser saves Orders.xlsx (sheet "Orders"), written without Office under App_Data/exports/ |
| Queue Q2 summary | a job appears (Running, then Done after ~3 s); View result ▸ opens it, Download result ⬇ saves it |
| Queue invoice batch ×1,204, then Queue monthly statement | the batch runs (~36 s, progress climbing) while the statement waits; the page stays responsive. Cancel selected stops the batch and the statement starts |
| Open second session ↗ → queue a job there | the new tab (owner sam) sees the same queue; the job appears in both tabs within a second |
Where things live
Module 6/
└─ OrderDesk.Web/ the Wisej.NET 4 app (net10.0-windows;net10.0), port 5606
├─ Program.cs / Startup.cs session entry point (Application.MainPage) / Kestrel host (app.UseWisej())
├─ Default.html / Default.json / Web.config ← appSettings OrderDesk.StorageRoot = "App_Data"
├─ Domain/ the reused business logic (OrderService.Save computes the imported totals)
├─ Files/StorageRoot.cs the configured root: Path.Combine(Application.StartupPath, …), uploads/ exports/ reports/, SafeFileName
├─ Files/OrdersCsvImporter.cs Stream → orders (two layouts) → CustomerService.FindByName + OrderService.Save
├─ Reporting/ReportService.cs CreateOrdersWorkbook(rows) → path · CreateInvoicePdf(order) → bytes
├─ Reporting/XlsxWriter.cs dependency-free .xlsx (ZipArchive + five OpenXML parts)
├─ Reporting/InvoicePdfWriter.cs dependency-free PDF (+ WritePages for batches)
├─ Reporting/ReportQueue.cs process-wide queue: one lock, one Task.Run worker, progress, cancel
├─ Reporting/ReportBuilders.cs the three jobs (invoice batch, monthly statement, Q2 summary)
├─ Views/InvoicePreviewForm.cs PdfViewer + Download in a modal Form (caller disposes)
├─ Views/Ui.cs colours + toast helper
├─ wwwroot/samples/order-batch.csv the sample import file (8 rows → 5 orders)
├─ MainPage.cs / .Designer.cs import, invoice, export and the report queue
├─ App_Data/ created at run time: uploads/, exports/Orders-<stamp>.xlsx, reports/<id>-<name>.pdf
└─ docs/ the lab deliverables + migration-log.md
Runtime facts
- Upload:
Wisej.Web.Uploadis a button that opens the browser's picker;AllowedFileTypes = ".csv"andMaxFileSize = 1048576filter on the client (Errorfires withFileTooLarge), the server validates again.Uploadeddeliverse.Files[i]withFileName,ContentLength,ContentType,InputStream. - PdfViewer:
PdfStream = new MemoryStream(bytes)inside aFormshown withShowDialog((form, result) => form.Dispose()). - Download:
Application.Download(path, name)streams a file from the server disk;Application.Download(stream, name)streams bytes in memory. - The queue worker never touches controls. It runs in
Task.Run, outside any Wisej session; pages poll it with aWisej.Web.Timerand redraw only whenReportQueue.Signature()changes. - Paths:
Path.Combine(Application.StartupPath, "App_Data", …)everywhere;Web.configOrderDesk.StorageRootmay be relative or absolute. - The projects multi-target
net10.0-windows;net10.0, sodotnet runneeds-f net10.0(or-f net10.0-windows). DeleteApp_Data/to reset uploads, exports and report results.