
Build a complete distributed app using aspire with .NET services and Next.js, featuring keycloak-based login in a Stack Overflow–style Q&A forum with a rich text editor and code blocks.
Identify prerequisites for this training, including coding and .NET experience, Next.js and React familiarity, and hardware requirements to run a distributed app with Docker or Podman.
Set up the development environment for a distributed .NET Aspire app by installing Rider or Visual Studio, Docker, Node.js, Postman, and Git.
Download the assets zip from the resources tab to access the overflow assets, including challenges, deployment, postman, slides, and source code. Review GitHub commits to track milestones.
Set up and configure aspire to orchestrate and host services, introducing Keycloak as the first identity provider and enabling login via Postman to obtain access tokens.
Explore aspire, an opinionated dotnet app host for distributed systems, delivering a single host to wire services, databases, caches, and dashboards with built-in monitoring, tracing, health checks, and plug-and-play integrations.
Create an Aspire project with dotnet nine and the 13.1 templates, set up the app host and services, and explore the Aspire dashboard for logs and metrics.
Explore how Keycloak implements OAuth 2.0, detailing resource owner, client, authorization server, and resource server roles, the authorization code flow, tokens, scopes, consent, and OpenID Connect integration.
Set up the aspire keycloak hosting integration to issue tokens, enable service discovery, and persist data with a Docker volume, then access the admin console.
Configure Keycloak by creating a permanent admin, logging in, then create and switch to a new realm named overflow, add test users, set passwords, and prepare for login testing.
Test login with a Keycloak client 'postman' using the resource owner password credentials grant in postman, obtaining an access token that expires in five minutes for bearer authentication.
Configure the access token by adjusting client scopes, audience, and roles in Keycloak, then evaluate the token contents in Postman and verify audience and role data.
Configure roles in the realm by creating member and admin groups in Keycloak, assigning users, and mapping group membership to access token roles via client scopes.
Save your work to source control by creating a public GitHub repository, committing changes, renaming master to main, and pushing to the remote to make your code available.
Set up and configure a spire with Keycloak, test obtaining an access token via postman, and review OAuth 2.0 realms while preparing to add the first .NET service.
Create the first net service in the distributed app using aspire, with Keycloak authentication. Implement crud for questions, answers, and tags in a single Postgres-backed service.
Create a question service with full CRUD using entity framework, linking questions to answers and tags, secured by Keycloak tokens integrated with the Aspire app host.
Integrate Keycloak into the new .NET web api using the Aspire Keycloak integration, configure JWT bearer authentication on port 7001, and verify endpoints with Postman.
Test authentication with Postman to diagnose 401 errors, verify bearer tokens from Keycloak, and use traces to understand Aspire 13.1 http/https issues and token expiry.
Add a Postgres database using Aspire hosting, set up an app host Postgres server with EF core migrations, and manage the database via Pgadmin for the question service's CRUD operations.
Define question and tag entity classes and a DbContext with DbSets for questions and tags in a Postgres database. Use migrations and seed data to power the question service.
Seed static tags via on model creating and has data using the model builder, then configure the question db context, create and migrate an initial migration, seeding data at startup.
Create a questions controller in an asp.net core web api, implement a create question post endpoint with a dto, authorize users, and persist the question to the database.
Attach a debugger to the Aspire service, inspect user claims to retrieve id and name, bind the create question DTO, save the question, return 201.
Validate user input on the backend with data validation attributes on the create question dto and a custom tag list validator (one to five), then verify tags against the database.
Implement get endpoints for questions, including optional tag filtering and by-id retrieval, with efficient view-count updates via EF Core 7. Add a tags controller returning ordered tags for anonymous access.
Add update and delete endpoints for questions in the question service, enforce authorization and user ownership, validate tags, and return 204 no content or 403 forbidden as part of crud.
We implemented the first net service, configured Keycloak authentication for resource creation, built CRUD for questions and tags, and proved Aspire wiring; next, we add a search service for questions.
Configure aspire's search service with type sense, creating an in-memory, typo-tolerant index. Use RabbitMQ to asynchronously update the index on question changes and expose a fast search endpoint.
Add in-memory search to the Aspire app with Typesense via a Docker container, replacing Elasticsearch, configure persistence, cors, and service discovery, and build a minimal API search service.
Configure the search service to expose type sense via http, install the dotnet type sense client, and wire its uri from configuration to enable external access.
Securely store and access an API key with dotnet user secrets in development, avoiding config-file exposure and passing the key to the TypeSense search service via environment variables.
Explore Type Sense dashboard to connect to Type Sense server over HTTP on port 8108, manage collections and indexes, and understand messaging with a service bus in a distributed app.
Configure a Typesense search for questions by defining a search question model with id, title, content, tags, createdAt, hasAcceptedAnswer, and answerCount; ensure the questions schema is created on startup.
Configure a minimal api endpoint at /search with the type sense client to return results, using title and content, and filter by a tag via regex.
Install the Aspire hosting RabbitMQ integration in app host, configure a data-persisting service bus, and use Wolverine FX to enable durable messaging and a transactional outbox for asynchronous service updates.
Learn to integrate WolverineFx into the question and search services, publishing messages to the RabbitMQ exchange 'questions' and binding them to queues for cross-service communication, with OpenTelemetry support.
Create a question created message handler in the search service with Wolverine discovery, define a question created contract, and index a stripped HTML document into the search index.
Explore how to publish messages across services using the iMessage bus with Wolverine, implement a transactional outbox, and ensure reliable, asynchronous communication between the question service, search service, and RabbitMQ.
Cache tag data in memory after the first database fetch with a two-hour expiration. Use a tag service to validate tags and enable tracing.
Implement edit and delete handlers for questions using a messaging system, update the search index with sanitized content and tags, and publish question updated and deleted events.
Add a similar title search endpoint in the minimal api search service using a TypeSense client. Handle errors with try-catch and perform partial updates with an anonymous object.
Configure the search net service in aspire, implement type sense for lightweight search, set up the search endpoint with RabbitMQ updates on question CRUD, and enable database content search.
Kick off the section five challenge to implement answer management in a distributed .NET app, using service bus to update the search service and enforce answer deletion rules.
Build an answer workflow in the .NET app by adding answer entities, migrations, and eager loading, with authorized endpoints to post, update, delete, and accept answers and publish events.
Deploy your existing project on Docker Compose from your dev machine using Aspire, set up a YARP gateway and Nginx proxy, and verify deployability and service health across containers.
Learn to implement robust error handling and test API responses in a .net microservice setup using docker compose, with a client-side interface and reverse proxies for consistent API routing.
Discover how to add Yarp as a reverse proxy in Aspire 9.4, migrating from config files to code-based routes for questions, tags, and search, with environment port setup.
Learn to deploy a .NET Aspire app locally with Docker Compose using Aspire 13 enhancements, configure Docker hosting, and publish a Docker Compose via the Aspire Publish tool.
Deploy and run your .NET services in Docker with the Aspire deploy command, using docker compose and the infra folder for production, while addressing Keycloak configuration and basic resiliency.
Configure Keycloak in docker using environment variables, expose port 6001 (internal 8080) via Aspire deployment, create prod admin user, and prepare exporting the development overflow realm to production.
Export the overflow realm from development to production Keycloak using Docker Compose. Verify the import with logs and an access token.
Implement Polly-based retry resiliency to ensure rabbitmq is available before service startup, handling broker unreachable and socket exceptions with exponential backoff and logging.
Create a common class library to share Wolverine, RabbitMQ, Polly, and OpenTelemetry setup, add a UseWolverine with RabbitMQ extension, and configure retries and a questions exchange.
Test docker compose services via postman, fix 401 unauthorized by aligning Keycloak issuers, implement a shared auth extension, and confirm all 22 tests pass.
set up an automated nginx proxy container for docker compose to expose services via virtual hosts, routing requests from port 80 to internal ports 8001, with host file tweaks.
Deploy an Aspire project with Docker Compose for local development. Start services with Aspire, manage Keycloak endpoints, run tests, and update gitignore to protect EMV production and overflow realm JSON.
Deploy a containerized dotnet app on the dev machine using docker compose, configure yarp and nginx proxies, and expose keycloak, the gateway, and the web app; prepare the Next.js client.
Build the section seven user interface with Next.js to display backend data via server-side rendering and client-side React, using tailwind and hero UI, integrated with aspire.
Create a Next.js client and server side web app, configure TypeScript and Tailwind, and run the dev server on port 3000, integrating Aspire hosting JavaScript.
Clean and configure a Next.js web app template, strip defaults, adjust layout and metadata, remove unused fonts, enable Tailwind, and introduce hero ui components to ready the Aspire user interface.
Install hero ui and hero icons manually, configure tailwind, and set up a hero ui provider to wrap a Next.js app, then use hero ui buttons and icons.
Structure your .Net Aspire app by creating a routable app folder and a reusable top nav bar, styling with Tailwind and flexbox, including links, search, and login and register actions.
Build a client-side side menu using Hero UI's ListBox in a Next.js app, wiring navigation links with icons, aria labeling, and active highlighting via Next.js navigation.
Fetch questions from an API in a Next.js app using server actions and use server, generate TypeScript types from Postman data, and render an SEO-friendly questions page.
Create and style interactive question cards using a dedicated component, pass in question props, display votes, answers, views, tags, and author info, with a responsive layout and links.
Learn to conditionally style elements in a React app using the cls utility, installed via npm install cls, applying always-on and conditional classes for accepted questions and a check icon.
Add a questions header with tabs for newest, active, and answered, displaying total and an ask question button, while supporting tag filtering via the query string.
Learn to add theming support with Next themes and hero UI, implement a theme provider and a navbar theme toggle, and handle client-side mounting and hydration issues.
Override Next.js default 404 by creating a custom not-found.tsx component, styling a centered layout with a go home link, and addressing server and client component constraints in Next.js 16.
Create a dynamic question detail page using a Next.js route parameter, fetch the question by id, and render a detailed header with title and view count.
Create a reusable React question detail component with fixed-width buttons, voting controls, and HTML content rendering via Tailwind Typography for light and dark modes.
Learn to add answer content to questions by building a reusable answer content component, display and style answers with voting, accepted indicators, and an answers header with sorting options.
Add question and answer footers to the user interface, displaying who asked or answered, tags, and user details, using TypeScript props and footer components in a .NET Aspire distributed app.
Enhance the home page with a centered layout, a giant icon and bold welcome text using Tailwind utilities, setting up future features like search and tags.
Build the user interface that consumes back-end services and displays data, laying out the initial structure with Tailwind CSS. Next, implement UI features without authentication.
Explore Next.js error handling for server actions invoked from client components, use transition for non blocking updates, and implement caching and custom 404/500 error pages.
Create a reusable fetch client in the Next.js app, using an environment variable API URL, TypeScript typing, proper headers, and robust error handling for server-side to server-side API calls.
Learn to implement user-friendly error handling in Next.js with an error boundary and a custom error page (error.tsx) that surfaces fetch errors and provides a retry option.
Test client side error handling by triggering errors via a dedicated action, using use transition for routing, and clarifying server versus client side environment configuration.
Redesign the fetch client to return data or an optional error, enabling flexible client-side handling (toasts vs redirects) and status-based fallbacks for 404 and 500.
Explore client side error handling in a distributed .NET app by implementing per-button loading, toast notifications with hero UI, and a reusable error helper for server errors.
Fetches and displays tags by building a server action, defining a tag type with id, name, slug, and description, and rendering them in a tailwind grid with card components.
Use Zustand to create a tag store in a Next.js app, enabling fetch, storage, and retrieval of tags and descriptions by slug, and display the tag description in the header.
Explore Next.js caching, including request memoization, router and data caches, and how force cache and revalidate reduce API calls and persist data.
Learn to format dates from Postgres UTC results using date-fns, create fuzzy time ago utilities (today, yesterday, days, weeks, months), and apply them to question and answer headers and footers.
Make the search input a controlled, debounced component by wiring a query state to an input, calling a search questions service, and showing loading and a results dropdown.
Improve the search experience by replacing the unordered list with a div-styled container and a hero UI list box, and redirect to selected question details while clearing the search input.
Master error handling in a Next.js app by returning serializable objects and using toasts and the error boundary, while leveraging a fetch client, caching, and client-side state before authentication.
Enable client-side authentication in a Next.js app with auth js to log in to Keycloak, obtain an access token, refresh sessions, and register users for backend access.
Configure a Next.js client in Keycloak to enable OpenID Connect authorization code flow with confidential access, set redirect URLs and issuer for the overflow realm, and configure Keycloak env vars.
Integrate authentication in your Next.js app using auth.js, install next-auth beta, configure environment secrets, and set up API routes and a Keycloak provider to enable secure sessions.
Create a client-side login button in the navbar using next-auth react for Keycloak. Configure signIn with a redirect to /questions and resolve issuer errors.
Learn to fetch the user session via an async get current user in the auth flow, handle missing sessions and errors, and display the user name in the top navigation.
Add a dropdown user menu in the navigation with a hero UI avatar and name, wiring sign out and login using next auth and session access token.
Display and inspect the auth session in the app by asynchronously fetching the session, rendering it as json, and preparing to include the access token for bearer authentication.
Learn to store the backend access token in the JWT and session by updating Next.js auth callbacks, ensuring the session exposes the access token for authenticated API requests.
Update the fetch client to attach the access token as a bearer authorization header for authenticated API requests, and improve 401 error handling with descriptive messages.
Explain configuring Keycloak audiences and access token lifespans, test token expiry and grace periods, and introduce refresh tokens and offline sessions to extend authentication beyond short lifetimes.
Implement a robust refresh token flow in a .NET Aspire distributed app using Keycloak with NextAuth.js, enabling seamless access token refresh and offline access for up to 30 days.
Register users with Keycloak by enabling realm registration, adding a nav register button that redirects to Keycloak's registration form via OpenID Connect endpoint, and returning to the app after signup.
Complete section nine by enabling client-side authentication with Keycloak in a Next.js app, enabling login, authenticated backend requests, refresh tokens, and short-lived access tokens via OAuth 2.0 and OpenID Connect.
Enable client-side CRUD for questions and answers with a rich text editor and image uploads, using react-hook-form, Tip Tap, and Cloudinary, and invalidate cache while updating the search index.
Add an authenticated question form with client-side components, including tag selection via Hero UI and a temporary text area, preparing to replace with a rich text editor.
Use React Hook Form and Zod to turn a simple form into a functional, validated one, with a form that has three inputs, register inputs, on submit, and schema validation.
Validate form inputs with a Zod resolver in React Hook Form, covering title, content, and tags; show errors with hero UI and disable submit until the form is valid.
Replace the text area with a headless rich text editor using tip tap. Integrate the open-source starter kit, adjust styling, and address hydration with immediately render false.
Add a rich text editor toolbar with a menu bar component, wiring bold, italic, strike, and code block to the editor state using Tip Tap; prepare for form validation.
Hook up the rich text editor to the form by turning it into a controlled input, wiring onchange and onblur, and binding the editor value to the form field.
Validate the rich text editor by wiring field state and error messages, applying conditional styling, stripping html tags, and refining the zod schema to handle undefined and enforce minimum content.
Post questions to the API using a post request to /questions, validate inputs with Zod, and redirect to the new question page after creation.
Sanitize html on the server with an html sanitizer to prevent scripts from executing when using dangerously set inner html.
Edit questions by syncing the current user ID from the auth profile into the token, auto-fill the edit form, perform a put update, and manage submission state with use transition.
Implement a client-side delete question button that calls a delete endpoint using a question ID, shows a loading transition, and redirects after deletion, while separating client and server components.
Extend the rich text editor with image upload using Cloudinary, add a TipTap image extension, install Next Cloudinary, and create a signed upload API route.
Enable image upload and link insertion in the rich text editor using Cloudinary widgets, update editor state with secure urls, and handle errors while planning image deletion cleanup.
Delete images from the rich text editor by extracting Cloudinary public IDs from image URLs with a regex, then call an API to destroy the image in Cloudinary.
Add an answer form to post answers for questions using an answer schema with the same content validation, posting to /questions/{id}/answers, in a client component.
Implement cache revalidation in Next.js by posting an answer, awaiting the response, then revalidating the questions path for the updated content and refreshing the UI.
Implement editing and deleting of user answers by adding edit and delete buttons, connecting the answer footer to the answer form, and scrolling to the form for updates.
Enable CRUD operations for questions and answers with a rich text editor supporting images and code blocks, while using revalidate path to invalidate cache and moving toward Docker Compose deployment.
Are you ready to take your .NET skills to the next level and build modern distributed applications?
In this hands-on course, you’ll learn how to design and develop a real-world, Stack Overflow–style app using the latest technologies in the .NET ecosystem and beyond.
We’ll start from scratch and guide you step by step through building a complete system with .NET 9, Aspire and WolverineFx. You’ll discover how to structure microservices, implement event-driven messaging, and manage data with PostgreSQL — all while keeping your application scalable and reliable.
On the front end, you’ll build a modern UI using Next.js (App Router), styled with Tailwind, and managed with Zustand for state management. Along the way, you’ll integrate Keycloak for secure authentication and authorization, giving your app production-ready identity features.
By the end of this course, you will not only understand the theory behind distributed systems but also have a fully working application that you can run locally with Docker or deploy to the cloud. More importantly, you’ll gain the practical skills to build, extend, and scale real-world systems in your own projects or career.
Whether you’re a .NET developer looking to level up, a full-stack developer curious about Aspire, or simply someone who wants to see how all the pieces fit together in a modern distributed system — this course is for you.
Enroll today, and let’s start building the future of apps with .NET Aspire and Next.js!