{"id":17337860,"url":"https://github.com/edwinvw/pitstop-engineering-workshop","last_synced_at":"2026-02-02T07:33:55.780Z","repository":{"id":89604032,"uuid":"220965890","full_name":"EdwinVW/pitstop-engineering-workshop","owner":"EdwinVW","description":"This is an engineering workshop based on the Pitstop sample application.","archived":false,"fork":false,"pushed_at":"2024-03-26T11:03:11.000Z","size":659,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-02T16:47:59.288Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EdwinVW.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-11-11T11:25:54.000Z","updated_at":"2022-09-14T11:38:47.000Z","dependencies_parsed_at":"2024-03-26T12:27:00.380Z","dependency_job_id":"8563aa09-0e80-4d28-8e8d-b13972a6b5e0","html_url":"https://github.com/EdwinVW/pitstop-engineering-workshop","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/EdwinVW/pitstop-engineering-workshop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdwinVW%2Fpitstop-engineering-workshop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdwinVW%2Fpitstop-engineering-workshop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdwinVW%2Fpitstop-engineering-workshop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdwinVW%2Fpitstop-engineering-workshop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EdwinVW","download_url":"https://codeload.github.com/EdwinVW/pitstop-engineering-workshop/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EdwinVW%2Fpitstop-engineering-workshop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29007306,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-02T06:37:10.400Z","status":"ssl_error","status_checked_at":"2026-02-02T06:37:09.383Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-15T15:36:26.008Z","updated_at":"2026-02-02T07:33:55.731Z","avatar_url":"https://github.com/EdwinVW.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pitstop engineering workshop\nThis document describes an engineering workshop that can be used for training .NET engineers and getting them up to speed on several cloud-native software-architecture aspects and how to develop and run software using containerization technologies like Docker and Kubernetes.\n\nIn most workshops you start from scratch, but in this workshop you will actually start with a complete working solution called Pitstop. You will learn by executing several labs in which you will be adding functionality to the solution. Any changes you make will only exist in your personal fork and must never be merged back into the actual Pitstop repository. The workshop is purely meant for learning new skills.\n\nPitstop is an open-source .NET sample application that demonstrates the following software-architecture aspects:\n\n- Microservices\n- Event-driven architecture\n- Domain Driven Design\n- Onion architecture\n- CQRS\n- Event-sourcing\n\nAlso, Pitstop demonstrates how to develop and deploy applications using several deployment technologies:\n\n- Docker\n- Docker-compose\n- Kubernetes\n- Service-mesh (Istio \u0026 Linkerd)\n\n# Labs\nIn order to complete the labs, make sure you read (at least) the following sections of the [Pitstop wiki on Github](https://github.com/EdwinVW/pitstop/wiki):\n\n- [Start page](https://github.com/EdwinVW/pitstop/wiki/Home)\n- [Application functionality](https://github.com/EdwinVW/pitstop/wiki/Application%20functionality)\n- [Domain description](https://github.com/EdwinVW/pitstop/wiki/Domain%20description)\n- [Solution architecture](https://github.com/EdwinVW/pitstop/wiki/Solution%20Architecture)\n- [Technology used](https://github.com/EdwinVW/pitstop/wiki/Technology%20used)\n\nBy now, you should have some understanding of what the Pitstop solution contains and what functionality it offers. Next you will execute several lab assignments in which you will add stuff to the Pitstop solution.\n\n## Lab 0: Preparation\nThere are some prerequisites for this workshop. First you need an active Internet connection. Additionally you will need to install the following software on your laptop:\n\n- Docker Desktop\n- Git client\n- Visual Studio Code\n- .NET SDK\n\n\u003eIf you already have satisfied these prerequisites, you can skip Lab 0 and go directly to Lab 1. \n\n### Step 0.1: Install prerequisites\nInstall the following software (if not already installed) on your laptop: \n\n#### Docker Desktop\nDownload link: [Docker Desktop](https://www.docker.com/products/docker-desktop). \n\nInstall Docker Desktop on your machine. If you are running Windows, you're free to choose whether you want to use WSL2 or not.\n\nDuring the installation, do NOT switch to Windows containers. We will only use Linux containers.\n\nAfter the installation and starting Docker, make sure Docker runs correctly by entering this command in a command shell:\n\n```console\ndocker run hello-world\n```\n\nIf you get any errors when running this command, check out the Docker documentation to see what the problem is.\n\n#### Git client\nInstall the Git client for your OS to interact with the Pitstop repo on Github.\n\nDownload link: [Git](https://git-scm.com/downloads)\n\n#### Visual Studio Code\nThis workshop assumes you are working with Visual Studio Code.\n\nDownload link: [Visual Studio Code](https://visualstudio.microsoft.com/downloads)\n\nAlso install the [C#](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) extension for VS Code.\n\n#### .NET SDK\nInstall the version of the .NET SDK that was used for PitStop (see [Technology used](https://github.com/EdwinVW/pitstop/wiki/Technology%20used)). \n\nDownload link: [.NET SDK](https://www.microsoft.com/net/download)\n\n### Step 0.2: Access Github\nIf you do not already have a Github account, create one by going to the [Github website](https://www.github.com) and click on the *Sign up* link in the top right corner. Make sure you are logged into Github with your account. \n\n## Lab 1: Run the applicaton\nIn this lab we'll make sure you can run Pitstop on your machine.\n\n### Step 1.1: Get the sources\nGet the sources from Github onto your machine.\n\nFor this to work, you must have installed the Git client (see Step 0.1). \n1. Open your browser and navigate to the Pitstop repo on Github: [https://github.com/edwinvw/pitstop](https://github.com/edwinvw/pitstop).\n2. Click the *Fork* button.\n3. The repo is forked to your Github account. If you have multiple accounts, Github will ask which account to fork to.\n4. Click the green *Clone or download* button on the forked repo. A dialog is shown.\n5. Copy the repo URL to the clipboard. \n6. Open Visual Studio Code on your machine.\n7. Give the clone repo command by pressing `CTRL-Shift-P`, typing `Git Clone` and pressing `enter` to confirm. You will be asked to specify a repo URL.\n8. Paste the copied repo URL in the text-box and press `enter` to confirm.\n9. You will be asked to specify a folder for cloning the repo into. Select a folder and confirm. The repo will be cloned in this folder.\n10. When VS Code asks you to open the cloned repo, do that. Now you can start working with the repo.\n\nThis would be a good time to walk through the solution and see what's in there. In the [Wiki](https://github.com/EdwinVW/pitstop/wiki) of the repo, you can find an overview of the solution structure.\n\n\u003e CAUTION: When you push your changes to your fork of the repository, do not create any pull requests for merging your changes back to the original Pitstop repository. Any changes you make will only exist in your personal fork and must never be merged back into the actual Pitstop repository. The workshop is purely meant for learning new skills.\n\n### Step 1.2: Build the Docker images\nIn order to build the Docker images, follow the instructions in the ['Building the Docker images'](https://github.com/EdwinVW/pitstop/wiki/Building%20the%20Docker%20images) section in the repo's Wiki.\n\n### Step 1.3: Run the application\nIn order to run the application, follow the instructions in the ['Starting the application'](https://github.com/EdwinVW/pitstop/wiki/Run%20the%20application%20using%20using%20Docker%20Compose) section in the Wiki.\n\n### Step 1.4: Get to know the solution\nIn order to get to know the functionality of the application, make sure you have read the introduction of the solution in the repo's README file up to the *Technology* section. After that, follow the ['Testing the application'](https://github.com/EdwinVW/pitstop/wiki/Testing%20the%20application) section in the Wiki.\n\n## Lab 2: Add an event-handler for customer events\nWhen something happens within the Pitstop application that could be interesting for other parts of the system, an event is published to the message-broker. For instance: when a new customer is registered, a *CustomerRegistered* event is published. \n\nIn this lab you will add a service to the solution that will react to customer events. What we will do when the event is received is up to your imagination. For the workshop, we will keep it simple and just dump a message on the console. \n\nThe service we will build offers no API and can therefore be a simple console application (just as the existing *NotificationService* for instance).\n\n### Step 2.1: Create a new .NET application\nFirst we will add a new service to the solution. \n\n1. Open a command-prompt or Powershell window.\n2. Make sure you are in the `src` folder within the Pitstop repository.\n3. Use the `dotnet new` command to create a new .NET console application named *CustomerEventHandler*:\n   ```\n   dotnet new console -o CustomerEventHandler\n   ```\n   The output should look something like this:\n\n   ![](img/dotnet-new-customereventhandler.png)\n\nA new *CustomerEventHandler* folder will be created which contains a .NET project. Because the created project-type is a console application, the folder will only contain a project file (*CustomerEventHandler.csproj*) and a main program file (*Program.cs*). The default implementation generated by `dotnet new` is printing *'Hello World!'* to the console.\n\nYou can test the application by running it:\n\n```\ncd CustomerEventHandler\ndotnet run\n```\n\nThe output should look like this:\n\n![](img/dotnet-run-customereventhandler.png)\n\n### Step 2.2: Create event-handler\nNow that you've added a new .NET project to the solution, you can start implementing the business logic of the service. As stated, the 'business logic' will be fairly simple for this workshop.\n\n**Open the project in VS Code**\nLet's open Visual Studio Code to start coding:\n\n1. Start Visual Studio Code.\n2. Select *File*, *Open Folder* and select the *CustomerEventHandler* folder you created in step 2.1. \n   \n   \u003eVisual Studio Code might show you some dialogs about plugins that you can install. For now, just install all plugins that it suggests. It will also asks you to add some 'assets' it needs for building and debugging the project. Acknowledge this with 'Yes'. This will create a '.vscode' folder. You can ignore that folder for now.\n   \n3. Open the file *CustomerEventHandler.csproj* by double-clicking on it. This is the file that describes the project. It is pretty straightforward and clean.\n4. Start the application by pressing `F5`. The project will be built and started. You can see the output in the 'DEBUG CONSOLE' window that was automatically opened.\n\n**Add reference to the infrastructure package**\nThe CustomerEventHandler service will need to receive messages from the message-broker. I have created a nuget package (*Pitstop.Infrastructure*) that contains a library that will make it easy to implement this without any specific knowledge about RabbitMQ (the broker that is used in the solution). \n\nYou need to add a reference to the *Pitstop.Infrastructure.Messaging* nuget package. Execute the following steps to add a reference to the package: \n\n1. Open the terminal window in Visual Studio Code using the *Terminal* menu.\n2. Type the following command in this window: `dotnet add package PitStop.Infrastructure.Messaging`. \n3. Visual Studio Code will detect changes in the references and automatically restore the references.\n\n**Add event definition**\nNow you can start adding some business logic. First you need to add the definition of the events you want to handle. All messages that are sent over the message-broker are plain JSON. The *CustomerRegistered* event is defined as follows:\n\n```json\n{\n\t\"messageId\": \"guid\",\n\t\"messageType\": \"string\",\n\t\"customerId\" : \"string\",\n\t\"name\": \"string\",\n\t\"address\": \"string\",\n\t\"postalCode\": \"string\",\n\t\"city\": \"string\",\n\t\"telephoneNumber\": \"string\",\n\t\"emailAddress\": \"string\"\n}\n```\n\nYou need to define a C# class to hold this information. We will only use the *customer id* and *name* properties in our code, so in your event-definition you can skip the other customer properties.\n\nThe infrastructure package you referenced in the previous step contains an *Event* base-class for events. This class inherits from the *Message* base-class which contains the *MessageId* and *MessageType* properties (the message-type is inferred from the name of the class).\n\n1. Add a new *CustomerRegistered* class to your project.\n2. Derive this class from the Event base-class in the *Pitstop.Infrastructure.Messaging* library.\n2. Add the implementation of the event-class that only contains the *customerId* and *name* property of the customer.\n\n**Add a *CustomerManager* class that handles events**\nNow that you have a definition of the event, you will add a *CustomerManager* class that will get the events from the message-broker and handles them. The polling for messages and the handling of a message when it's available are abstracted in two separate interfaces: *IMessageHandler* and *IMessageHandlerCallback*. They are both defined in the infrastructure package.  \n\nThe *IMessageHandler* interface abstracts the polling for messages on a message-broker. An implementation of this interface will be passed into your *CustomerManager*'s constructor. The infrastructure package also contains an implementation of this interface that works with RabbitMQ. \n\nWhen you want to start listening for messages, you have to call the *Start()* method on this interface and pass in an implementation of the *IMessageHhandlerCallback* interface. The *HandleMessageAync()* method is called on the callback implementation when a message is available on the message-broker. The *CustomerManager* will implement this interface and handle the events.\n\nThis is a class diagram of this pattern:\n![](img/messaging-cd.png)\n\n1. Add a new *CustomerManager* class to your project.\n2. Add the implementation that handles *CustomerRegistered* messages. You can reference other event-handlers (e.g. *AuditlogService*) for inspiration.\n\n**Start the customermanager**\nNow that you created a *CustomerManager* that can handle *CustomerRegistered* events, you need to start this manager form the main program. You will use the *RabbitMQMessageHandler* class from the infrastructure package to pass into the *CustomerManager*. \n\n1. Open the *Program.cs* file in the project.\n2. Replace the existing code with the necessary code to setup and start the event-handler. You can reference other event-handlers (e.g. *AuditlogService*) for inspiration.\n\n**Build the code**\nIn order to check whether or not you made any mistakes until now, build the code. Do this by pressing `Ctrl-Shift-B` in Visual Studio Code and choosing the task *Build*. The output window should look like this:\n\n![](img/vscode-build.png) \n\n### Step 2.3: Run the service\nWe can start the *CustomerEventHandler* to test whether or not it works. \n\n1. Make sure you have the Pitstop application running on your machine (as described in Step 1.3: Run the application).\n2. Open a command prompt or Powershell window and go to the *CustomerEventHandler* folder.\n3. Start the application by giving the following command: `dotnet run`.\n4. Open the browser and go to http://localhost:7005 to open the Pitstop web-app.\n5. Go to the *Customer Management* tab and register a new customer.\n\nWatch the output window of your *CustomerEventHandler*. You should see that a message is printed to the console, something like this:\n\n![](img/dotnet-run-customereventhandler-broker.png) \n\nThat's it! You have now created a new service that can react on events emitted by the services in the Pitstop solution. Pretty sweet!\n\n### Step 2.4: Create Docker image\nNow that you have created a functional service, let's run it in a Docker container.\n\n1. Add a new file to the project named *Dockerfile*.\n2. Copy the contents of the dockerfile of the *AuditlogService* and make sure it starts the CustomerEventHandler (in the ENTRYPOINT statement).\n\n\u003e Please take some time to go over the Dockerfile now. You see an example of the Docker multi-stage build mechanism. \n\u003e - First it starts in a container that is based on an image that contains the full .NET SDK. We call this *build-env* for later reference.\n\u003e - After that it sets the folder */app* as the current working-folder for the build. It copies the *.csproj* file of your project into to the working-folder. \n\u003e - Then it restores all the dependencies by running `dotnet restore`. \n\u003e - After the restore, it copies the rest of the files to the working-folder and publishes the application by running `dotnet publish -c Release -o out`. It builds the *Release* configuration and outputs the result in the folder *out* within the working-folder.\n\u003e - Now it starts the second phase which runs in a container based on the .NET run-time container. This container does not contain the entire .NET SDK - so it's much smaller.\n\u003e - It then copies the output from the other build phase (that was called *build-env*) to the local folder within the container.\n\u003e - Finally it specifies the entry-point - the command to execute when the container starts. In this case it specifies the command `dotnet` and as argument the assembly that was created during the build. This will start the *CustomerEventHandler* console application you've created.\n\nNow you are going to build a Docker image using the Dockerfile.\n\n1. Open a command prompt or Powershell window and go to the *CustomerEventHandler* folder.\n2. Build a Docker image by entering the following command: \n\n\t`docker build --rm -t pitstop/customereventhandler:1.0 .`\n\n   \u003e You specify the name of the image using the *Tag* option (`-t`).\n3. Check whether the image is created by entering the following command: `docker images`:\n\n   ![](img/docker-images.png)\n\n### Step 2.5: Run the service in a Docker container\nNow that you have the Docker image, you can start a container based on this image. \n\n1. Run a Docker container based on the image by entering the following command:\n\n\t`docker run -it --rm --network src_default --name customereventhandler pitstop/customereventhandler:1.0`\n\n   \u003eIn this command you specify the virtual network to connect with. In this case we specify the name of the default network that was created by docker-compose when we started the solution (*src_default*). By doing this, the container can find and access the RabbitMQ server that is running in a separate Docker container on the virtual network.\n2. Open the browser and go to http://localhost:7005 to open the Pitstop web-app.\n3. Go to the *Customer Management* tab and register a new customer.\n\nWatch the output of your running container. You should see that message again that indicates that a customer was registered:\n\n![](img/docker-run.png)\n\n**Before you continue, stop the running container by pressing `Ctrl-C`.**\n\n### Step 2.6: Run the service using docker-compose\nThe last step in this lab is to extend the docker-compose file to include your service. \n\n1. Open the *docker-compose* file in the *src* folder of the Pitstop repo in Visual Studio Code.\n2. Add this snippet to the *docker-compose* file just before the webapp part:\n\n   ```\n     customereventhandler:\n       image: pitstop/customereventhandler:1.0\n       build: CustomerEventHandler\n       container_name: CustomerEventHandler\n       depends_on:\n         - rabbitmq\n       environment:\n         - DOTNET_ENVIRONMENT=Production    \n   ```\n3. Save the file.\n4. Open the Powershell window where you started the solution using `docker-compose up`.\n5. Stop the running solution by pressing `Ctrl-C` and wait until all the containers are stopped.\n6. Restart the solution by giving the command: `docker-compose up`. The *CustomerEventHandler* will be started together with all the other services.\n2. Open the browser and go to http://localhost:7005 to open the Pitstop web-app.\n3. Go to the *Customer Management* tab and register a new customer.\n\nWatch the docker-compose logging in the console. You should see that message again that indicates that a customer was registered:\n\n![](img/docker-compose-output.png)\n\n\u003eThe following labs are more advanced labs you can do on your own if you're done with the first two labs. There's no extensive description on how to complete these labs, only a description of the required outcome. It's up to you to figure out the best way to implement these requirements. \n\n## Lab 3 - Add update functionality to Pitstop\nThe current version of Pitstop only supports adding customers, vehicles and maintenance jobs. There is no way to update these. In this lab you have to add support for updating the data of customers, vehicles and maintenance jobs.\n\n1. Add Specflow features for this new functionality.\n2. Write the unit- and specflow-tests for testing this new functionality.\n2. Add the requested functionality.\n4. Extend the UI-tests with this new functionality.\n\n## Lab 4 - Add Inventory management\nDuring a maintenance job, a mechanic often uses products like: tires, windscreen-wipers, oil, oil-filters, etcetera. There is currently no way to support this in Pitstop. In this lab you have to add the ability for a mechanic to add products that he or she uses during the execution of a maintenance-job. For every product used, the inventory must be updated and the price of the products must be added to the bill that is sent to the customer. \n\nIn the context-map shown in the \u003ca href=\"https://github.com/EdwinVW/pitstop/wiki/Domain%20description\" target=\"_blank\"\u003edomain description\u003c/a\u003e on the Wiki, Inventory Management is shown (grayed out). Use this information in this assignment. \n\n1. Add Specflow features for this new functionality.\n2. Add an *InventoryManagement* service to the solution that can be used to manage the products in stock. \n3. Write the unit- and specflow-tests for testing this new functionality.\n4. Add the requested functionality.\n5. Extend the UI-tests with this new functionality.\n\n## Lab 5 - Deploy Pitstop to Azure\nUntil now, you've ran Pitstop in containers on your local machine. In this lab you will learn how to deploy a microservices application that consists of multiple parts (Pitstop) in Microsoft Azure. In a production scenario, using containers for running the app would be a fine solution. But in order to get you up-to-speed with different Azure services, you're not allowed to host the app in containers.\n\n- Follow the following courses in the Pluralsight library:\n\t- [AZ-103 - Azure Administrator](https://app.pluralsight.com/paths/certificate/microsoft-azure-administrator-az-103)\n\t- [AZ-203 - Developing Solutions for Microsoft Azure](https://app.pluralsight.com/paths/certificate/developing-solutions-for-microsoft-azure-az-203)\n- Request access to an Azure Subscription by asking approval from your business-unit manager and sending an email to [support@infosupport.com](mailto:support@infosupport.com).\n- Make a deployment diagram for deploying Pitstop as-is in Azure. A requirement is that you use Azure PAAS / SAAS services and do not use container-hosting services like ACI, ACA or AKS.\n- Send the deployment diagram to your supervisor for review.\n- Deploy Pitstop to Azure (and make sure the web-app is publicly available).\n- Share a link to the web-app with your supervisor. \n\n## Lab 6 - Setup a CI/CD pipeline\nModern applications are built using an automated CI pipeline and deployed using an automated CD pipeline. Azure DevOps is a tool to implement fully automated CI/CD pipelines. There an on-premises version and a cloud version. In this assignment you will setup a CI/CD pipeline for building and deploying Pitstop.  \n\n- Build a CI/CD pipeline in Azure DevOps to do a fully automated deployment of the necessary infrastructure (according to your diagram) for hosting Pitstop in Azure. Hint: use ARM templates. \n- Build a CI/CD pipeline in Azure DevOps to do a fully automated deployment of the Pitstop application on the provisioned infrastructure.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedwinvw%2Fpitstop-engineering-workshop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fedwinvw%2Fpitstop-engineering-workshop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedwinvw%2Fpitstop-engineering-workshop/lists"}