Most of my professional experience is in Java and Spring Boot. That's what I build with every day at work — microservices, REST APIs, Angular frontends. But the tech market right now rewards versatility, and I've had C# and .NET on my "want to learn" list for a while. So instead of just reading docs and doing tutorials, I did what I always do: I built something real.
BarKeep is a bar & grill ordering app. Customers can browse a menu of craft cocktails, appetizers, entrees, and desserts, add items to a cart, adjust quantities, and place orders. It's the kind of app that touches every layer of a web framework — routing, data binding, form handling, session state, dependency injection, partial views — which is exactly why I chose it. I didn't want a todo list. I wanted something that would force me to actually use the framework the way you would on a real project.
The app is built with ASP.NET Core 9 using Razor Pages, which is Microsoft's recommended approach for server-rendered, page-focused web apps. If you've used Spring MVC or even classic ASP.NET MVC, Razor Pages will feel familiar but more streamlined. Each page has a .cshtml view and a corresponding PageModel class that handles the GET and POST logic. There are no controllers — the page IS the endpoint. It's clean, convention-based, and surprisingly productive once you get the routing model down.
One of the things I focused on was writing the app the way an experienced .NET developer would, not just getting it to work. That meant using proper dependency injection for services (IMenuService, ICartService, IOrderService all registered in Program.cs), creating ViewComponents for dynamic navbar elements like the cart badge, extracting reusable partial views for menu cards and toast notifications, and using TempData for flash messages between redirects. These are patterns that separate a "first .NET project" from production-quality code.
The menu data lives in a JSON file that gets loaded by a singleton MenuService at startup. The cart and order data are session-based — no database required, which keeps the app simple to deploy while still demonstrating real state management patterns. Session is configured through ASP.NET Core's built-in middleware, and the cart service reads and writes to it through IHttpContextAccessor. It's a clean separation of concerns that would scale easily to a database-backed implementation.
On the frontend, I went with Bootstrap 5 in dark mode using the native data-bs-theme="dark" attribute, then layered on custom CSS to give it a modern, Shadcn-inspired look. The design uses a zinc color palette with blue accents, Inter font, sticky navbar with backdrop blur, responsive card layouts, and scroll-triggered CSS animations. The cart page has a dual layout — a table on desktop and a card-based design on mobile — because a five-column table on a phone is a terrible experience. I wanted the UI to feel like a real product, not a homework assignment.
Deploying was straightforward. The app runs on Render's free tier with automatic deploys from the GitHub repo. Every push to main triggers a build and redeploy. No Docker needed for this one — Render detects the .NET project and handles the build pipeline automatically.
Building BarKeep reinforced something I've noticed across every language and framework I've worked with: the patterns are more similar than they are different. Dependency injection in ASP.NET Core works almost identically to Spring Boot. Razor Pages' PageModel is conceptually the same as a Spring MVC controller. Session management, form binding, partial views — the syntax changes, but the architecture doesn't. If you already know one server-side framework well, picking up another is mostly about learning the conventions and tooling.
That said, there were things I genuinely appreciated about the .NET ecosystem. The dotnet CLI is excellent — scaffolding, building, running, and publishing all work smoothly from the terminal. Razor syntax for mixing C# and HTML is more natural than Thymeleaf or JSP. And the built-in tag helpers (asp-page, asp-route, asp-for) eliminate a lot of the boilerplate that you'd write manually in other frameworks. Visual Studio and JetBrains Rider both provide great tooling, but honestly, I did most of this project in VS Code and the CLI.
The whole point of this project was to demonstrate that I can be productive in C# and .NET, not just Java. In a market where a lot of enterprise shops run on .NET and many job listings ask for experience in both ecosystems, having a working project that shows real framework knowledge — not just syntax familiarity — matters. BarKeep isn't a massive app, but it covers the patterns that come up in every .NET interview: Razor Pages vs MVC, dependency injection lifetimes, middleware configuration, session state, and clean project structure.
If you want to check it out, the live app is at barkeep-idcz.onrender.com and the source code is on my GitHub. And if you're a Java developer thinking about picking up C#, my advice is simple: just build something. The frameworks will feel familiar, the ecosystem is mature, and having both on your resume opens doors that neither one can open alone.