From Check-In to Check-Out in a .NET Visitor System

In part 1, I showed how this visitor management system was put together: a WPF reception app, face recognition, ID card scanning, and an ASP.NET MVC admin portal sharing one SQL Server database.
This part follows a single visitor from the moment they walk in to the moment they leave.
Then I will be honest about what the system lacked, and how I would upgrade it today as a senior engineer.
The Reception Desk Setup
The reception PC ran a simple WPF app with three screens.
- A welcome screen that opened when the PC started.
- A camera preview showing the live webcam feed.
- One visitor form used for both new and returning visitors.
On the desk sat two devices.
- A Logitech HD 720p autofocus webcam. Its base could rotate, so the receptionist simply turned it toward the visitor.
- A hands-free barcode scanner on a stand, the kind you see at store checkouts. No trigger to press. You just hold the card in front of it.
The design goal was clear. The receptionist should spend as little time as possible on the keyboard and mouse.
Step 1: Hands-Free Face Capture
The receptionist asks the visitor to look at the webcam.
On the preview, a blue or green box appears around the visitor's face, with a line across the eyes. If the face is turned or too far away, the receptionist asks the visitor to adjust.
Then the important part. Nobody presses a button. As soon as the camera detects a proper face, the picture is taken automatically.
The Neurotechnology library extracts the face features it needs for matching. Our code then searches the database for a stored visitor with a matching face.
While the camera was working, its small activity light glowed, so everyone could see a scan was in progress.
The receptionist only turns the camera toward the visitor. No clicks, no typing.
Step 2: A Returning Visitor
If the face matches, the visitor's details load right away.
The receptionist does only two things.
- Selects the host the visitor came to meet.
- Saves the visit.
The visitor then hands over their national ID card, which stays at reception as part of the building's standard procedure. In return, they get a visitor card to wear.
Step 3: A New Visitor
If there is no match, the receptionist fills in the form.
- Types the visitor's name.
- Clicks into the ID number box.
- Holds the ID card in front of the scanner to read its barcode or QR code, or types the number by hand.
- Selects the host and saves.
When the card is scanned, the scanner returns more than just the ID number. Our function runs the regex from part 1 on the full scan, keeps only the ID number, and shows it in the text box.
Keeping manual typing as an option was a small but useful decision. A worn barcode should never stop a check-in.
Step 4: Check-Out With the Same Face
When the visit ends, the visitor comes back to reception. They return the visitor card and collect their ID card.
Before leaving, they look into the camera one more time. The system recognizes them, finds their open visit, marks them as left, and calculates the visit duration from the check-in and check-out times.
The same face scan decides whether someone is arriving or leaving. Here is the idea in a simplified form.
var visitor = faceService.FindMatch(capturedFace); if (visitor == null) { // Unknown face: this is a new visitor StartNewVisitorRegistration(capturedFace); return; } var openVisit = visitRepository.GetOpenVisit(visitor.Id); if (openVisit != null) { // Visitor already checked in: they are leaving openVisit.CheckOutTime = DateTime.Now; openVisit.Duration = openVisit.CheckOutTime.Value - openVisit.CheckInTime; visitRepository.Save(openVisit); } else { // Known visitor with no open visit: they are arriving StartRepeatVisit(visitor); } One camera, one face scan, two different meanings. The open visit record tells the system which one it is.
The Admin Side
The admin portal was where the gaps showed.
- A single fixed admin login.
- One visit report showing the visitor's details, the host, check-in time, check-out time, and duration.
- A basic date filter, as far as I remember.
- A search box that only searched data already loaded in the browser. It never sent a search to the server.
- Pagination with a fixed page size. There was no option to change the number of rows per page.
Honestly, it was basic. It did its job, but it was never polished. I was handling several projects at the same time, so the admin side never got the attention it deserved.
Here is what I would build today.
How I Would Upgrade It Today
1. Sync Hosts From the ERP
In part 1, I mentioned that the host list had to be updated by hand.
The fix is to pull hosts from the ERP automatically, with their department, job title, and photo.
This also solves a quieter problem. When two employees share the same name, a photo alone is not enough. With department and title, the receptionist can be sure they picked the right person.
2. Search Hosts by Department and Title in WPF
Once that data exists, the WPF host picker should use it. The receptionist types a few letters, filters by department, and finds the exact person in seconds.
3. A Proper Report
- Server-side search and filters. Searching only loaded data works with a few hundred rows. As visits grow into the thousands, sending everything to the browser gets slow. The database should do the filtering.
- Report settings, like choosing which columns to show and how many rows per page.
- Export to Excel and PDF, because managers always ask for a file.
4. A Live Dashboard
At a glance, the admin should see today's numbers.
- Total visits today.
- Visits in progress.
- Completed visits.
- The host with the most visitors today.
Here is a simplified SQL Server version, using an example schema.
DECLARE @Today date = CAST(GETDATE() AS date); -- Today's totals SELECT COUNT(*) AS TotalVisits, SUM(CASE WHEN CheckOutTime IS NULL THEN 1 ELSE 0 END) AS InProgress, SUM(CASE WHEN CheckOutTime IS NOT NULL THEN 1 ELSE 0 END) AS Completed FROM Visits WHERE CheckInTime >= @Today AND CheckInTime < DATEADD(DAY, 1, @Today); -- Busiest host today SELECT TOP (1) h.HostId, h.FullName, COUNT(*) AS VisitCount FROM Visits v JOIN Hosts h ON h.HostId = v.HostId WHERE v.CheckInTime >= @Today AND v.CheckInTime < DATEADD(DAY, 1, @Today) GROUP BY h.HostId, h.FullName ORDER BY VisitCount DESC; Two small details matter here.
- The date filter is a range, not
CAST(CheckInTime AS date) = @Today. Wrapping the column in a function can stop SQL Server from using an index on it. - The busiest host query groups by
HostId, not only by name. Two employees with the same name would otherwise be counted as one person. It is the same problem the ERP sync solves at the front desk.
5. Close Forgotten Check-Outs
Some visitors will leave without checking out. Their visits stay "in progress" forever and break the dashboard numbers.
A scheduled job at the end of each day can flag those visits for the admin to review.
Before and After
| Area | What it had | What I would build |
|---|---|---|
| Hosts | Typed in by hand | Synced from the ERP with department, title, and photo |
| Host picker | Names only | Search and filter by department and title |
| Report search | Browser only | Server-side search and filters |
| Report settings | Fixed | Columns, page size, Excel and PDF export |
| Overview | None | Live dashboard for today |
| Open visits | Stayed open | Daily check for forgotten check-outs |
Key Takeaways
- Hands-free capture made check-in fast. The best interface is sometimes no interface.
- One face scan handled both arrival and departure. The data decided the meaning, not an extra button.
- Manual input should stay available as a fallback.
- Browser-only search is fine for small data. Real reports need the database to do the work.
- Data that exists in another system, like employees, should be synced, not retyped.
- A system can work and still not be finished. Knowing the difference is part of growing as an engineer.
Over to You
If you inherited a basic admin report like this one, what would you add first: filters, exports, or a dashboard? Tell me in the comments.
This is the final part of the series. If you missed it, part 1 covers the architecture, the ID card regex, and the Windows Update problem.
If you are working on a similar system, or you are hiring a .NET developer who enjoys this kind of work, you can reach me through my website.
原文:https://www.a8q9.cn/en/article/from-check-in-to-check-out-in-a-net-visitor-system-df49d6.html