Skip to main content

Services, DI & Testable UI

Module 1's hand-written AppComposition factory is replaced by Application.Services registrations with explicit lifetimes; the screen asks for five capabilitiesITicketService, IUserService, IPermissionService, INotificationService, IAuditLogService — through [Inject] properties instead of creating concrete classes; each contract has a fake (in-memory) and a production-shaped implementation behind a registration profile chosen at startup; and the screen's decisions live in a plain TicketWorkflowPresenter that tests drive with fakes and no browser.

Nothing here is deployed anywhere; it is a plain Wisej.NET 4 project that runs on your machine. The "production" services are stand-ins that log the SQL / directory / SMTP calls they would make.

Run it

cd "LearnWisej-Samples/Production Architecture Deep Dive\Module 8\TicketOps"
dotnet run -f net10.0 --urls http://localhost:5108

Then open http://localhost:5108 (fake profile) or http://localhost:5108/?profile=production. (Visual Studio: open TicketOps.slnx, press F5 — the port is in Properties/launchSettings.json.)

Requirements: .NET 10 SDK, the Wisej-4 4.1.0 NuGet package.

What to try in the Ticket Workflow window

ActionWhat you should see
Select #1041, type a reason, Close ticketstatus ● Ticket #1041 closed.; the row leaves the grid
Select #1044, Assign to methe Assignee column shows Dana Reyes
Close ticket with an empty reasonbanner Give a reason before closing.
Select #1042 (no hours logged), give a reason, Close ticketorange banner Log hours before closing.
Signed in as → Sam Okafor (Viewer), then Close ticketred banner Sam Okafor (Viewer) may not close ticket #1041. — a second tab keeps its own operator
Open ?profile=production and repeatthe same screen and results; the server console shows would run: UPDATE dbo.Tickets …

Where things live

TicketOps/
├─ Views/TicketWorkflow the screen: [Inject] properties, thin handlers → presenter, ShowResult / ReportFailure
├─ Controls/StatusBanner reusable "● state" + banner UserControl (display only)
├─ Services/
│ ├─ ITicketService / FakeTicketService / SqlTicketService load & transition tickets (Session)
│ ├─ IUserService / FakeUserService / DirectoryUserService who is signed in (Session)
│ ├─ IPermissionService / FakePermissionService / RolePermissionService what they may do (Session)
│ ├─ INotificationService / FakeNotificationService / EmailNotificationService toasts & alerts (Transient)
│ ├─ IAuditLogService / FakeAuditLogService / SqlAuditLogService who did what, when (Shared)
│ ├─ TicketWorkflowPresenter.cs the screen's decisions: input → exists → permission → rule → audit → notify
│ └─ WorkflowResult.cs Ok / Invalid / Denied / NotFound + a message the user may read
├─ Domain/ Ticket (CanClose / Close / AssignTo), Operator, AuditEntry, Notification, OperationResult
├─ Data/ SeedData, TicketTable (in-memory table)
├─ Infrastructure/ ServiceRegistration, ActiveProfile, ILog / ActivityLog (Session service, server console)
├─ Diagnostics/PresenterTestRunner.cs the eight presenter tests, against fakes
├─ Resources/Strings.cs safe user-facing messages
├─ docs/ the deliverables
├─ Program.cs session entry point: pick the profile, register, new TicketWorkflow().Show()
└─ Startup.cs Kestrel host (app.UseWisej())