A visitor walks up to the reception desk. They look at the webcam for a moment.
Before they say a word, the system already knows if they have been here before.
If they are new, the receptionist scans their national ID card. The ID number fills itself in. No typing. No typos.
I did not build this system from scratch. Around 2018, it was handed over to me. From then on, I was solely responsible for its enhancements, modifications, bug fixes, and new features.
Owning someone else's system teaches you things that building your own never does. In this post, I will walk you through how it worked, the two problems that taught me the most, and what I would change if I built it today.
This is part 1 of a short series. Later parts go deeper into barcode scanning, face recognition, and reporting.
The Problem It Solved
Reception desks deal with the same issues every day.
- Typing ID numbers by hand. National ID numbers are long. One wrong digit makes the record useless.
- No memory of past visitors. A returning visitor had to give the same details again and again.
- No clear reporting. Management wanted to know who visited, when, and how often.
The goal was simple. Make check-in fast, accurate, and traceable.
The Architecture
The system had three main parts.
- WPF reception app. It ran on the reception PC, with a webcam and a desktop barcode scanner attached. The scanner was the same kind stores use to scan products.
- ASP.NET MVC admin portal. Administrators used it to view daily and monthly visitor reports.
- One shared SQL Server database. Both apps read and wrote to the same database. There was no API layer between them.
Both apps were built on .NET Framework 4.7.
Why a shared database? I did not make that choice, but I understand it. Both apps needed the same data, and a shared database is the fastest way to ship. I will come back to this design later, because today I would do it differently.
The Visitor Flow
Here is what happened at the desk, step by step.
- The visitor looks at the webcam.
- The app captures the face and checks it against stored visitors using the Neurotechnology face recognition SDK.
- Returning visitor: their details load right away. The receptionist confirms the visit and selects the host.
- New visitor: the receptionist asks for their details and their national ID card.
- The receptionist scans the barcode or QR code on the ID card. The ID number fills in automatically.
- The visit is saved to the database. It then shows up in the admin portal reports.
Here is the decision logic in a simplified form. The real code had more validation, but the idea is the same.
var match = faceService.FindMatch(capturedFace);
if (match != null)
{
// Returning visitor: load saved details
ShowReturningVisitor(match.VisitorId);
}
else
{
// New visitor: start registration and keep the face template
StartNewVisitorRegistration(capturedFace);
}
Scanning the ID Card
Every citizen has a unique numeric national ID number. Many ID cards carry it in a barcode, and some carry it in a QR code.
The catch is that the code holds more than the ID number. A scan returns extra details along with it. The app needed only the ID number.
So I used a regular expression to pull out just the part I needed.
using System.Text.RegularExpressions;
public static class IdCardParser
{
// Example: a 13 digit ID number.
// Adjust the length to match your country's ID format.
private static readonly Regex IdPattern =
new Regex(@"(?<!\d)\d{13}(?!\d)", RegexOptions.Compiled);
public static string ExtractNationalId(string scannedText)
{
if (string.IsNullOrWhiteSpace(scannedText))
return null;
Match match = IdPattern.Match(scannedText);
return match.Success ? match.Value : null;
}
}
The lookarounds (?<!\d) and (?!\d) matter. They make sure we match exactly 13 digits, not 13 digits taken from the middle of a longer number.
This one small step removed manual typing at the desk. It also removed the typing errors that came with it.
Two Problems That Taught Me the Most
1. A Windows Update Could Break Face Recognition
This was the hardest technical issue.
The Neurotechnology libraries needed a specific .NET Framework version. If Windows Update installed a newer .NET Framework version on the reception PC, face scanning and matching stopped working.
Our fix during implementation was to keep Windows Updates turned off on the reception PCs.
It worked. But it was a trade-off. A PC without updates also misses security patches.
Lesson: when your app depends on a third party SDK, the runtime version is part of your system. Plan for it from day one.
2. The Host List Lived in Its Own Island
Every visitor comes to meet someone. That person is the host.
The system had no integration with the company's ERP. So when an employee joined or left, the VMS administrator had to update the host list by hand.
That works on day one. Over time, it means outdated hosts, missing new joiners, and extra admin work.
Lesson: any list of people that already exists somewhere else should be synced, not copied by hand.
What I Would Do Differently Today
Looking back, the system did its job. But my thinking has grown since then. Here is what I would change.
- Add an API layer. Instead of two apps sharing one database, the admin portal and the desk app would talk through an ASP.NET Core Web API. That gives one place for business rules and security.
- Control the runtime, not the whole OS. Modern .NET supports self contained deployment, so the app ships with its own runtime. Operating system updates could then install without changing the version the app depends on. This assumes the SDK supports modern .NET, which I would confirm first.
- Manage updates instead of blocking them. If the runtime must stay fixed, I would hold back specific updates through group policy and test them on a staging PC first, rather than turning off all updates.
- Sync hosts automatically. A scheduled import or an API from the ERP or HR system would keep the host list current with no manual work.
- Treat face data as sensitive from the start. I would make clear retention and consent rules a day one requirement, not an afterthought.
Key Takeaways
- Small automations, like scanning an ID instead of typing it, remove a whole class of errors.
- Third party SDKs bring hidden constraints. Know them before deployment.
- A shared database is fast to start with, but an API layer scales better.
- Data that already exists in another system should be integrated, not retyped.
- Inheriting a system is a fast way to learn. You see decisions you would not make yourself, and you learn why they were made.
- Looking back at old projects honestly is one of the best ways to grow.
Over to You
Have you ever had a Windows or framework update break a hardware or SDK integration? How did you handle it? Tell me in the comments.
In the next part, I will go deeper into barcode and QR code scanning in a WPF app. Follow me so you do not miss it.
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.


Top comments (0)