Fixing the “Configuring CI/CD Pipelines as Code with YAML” Lab for AZ-400

Fixing the “Configuring CI/CD Pipelines as Code with YAML” Lab for AZ-400

If you are grinding through AZ-400 exam labs and relying on the Azure DevOps Demo Generator, you already know Microsoft officially discontinued the web-hosted version. Pulling down the open-source .NET console application to spin up the PartsUnlimited template is the only way forward—but the legacy code immediately triggers a cascade of build failures on modern infrastructure.

Welcome back to Terminal Notes. Here is the complete step-by-step guide to fixing the legacy dependencies, correcting the YAML pipelines, and surviving the Azure SQL serverless cold starts.

1. Updating the Microsoft-hosted agent image

Error

  • No image label found to route agent pool Azure Pipelines.
    • Pool: Azure Pipelines
    • Image: vs2017-win2016

Cause of the Error

  • The vs2017-win2016 (Visual Studio 2017 on Windows Server 2016) Microsoft-hosted agent image has been permanently retired and removed from Azure DevOps.
  • Because this image label no longer exists in the Microsoft-hosted pool, the pipeline automatically fails when attempting to route the job.

How to Fix It

  • Open your Azure Pipeline YAML file or the Classic UI pipeline settings.
  • Update the Agent Specification (or vmImage) to a currently supported Microsoft-hosted image.
  • windows-2019: The closest direct alternative, containing Visual Studio 2019.
  • windows-latest (or windows-2022): The standard current image for modern Windows builds.

YAML Configuration Update Change your pipeline pool from:

YAML

pool:
  vmImage: 'vs2017-win2016'

To a supported version:

YAML

pool:
  vmImage: 'windows-latest'

2. Upgrading the Legacy .NET Framework (MSB3644)

The default PartsUnlimited template is hardcoded to .NET Framework 4.5.1 and 4.6.1. Modern windows-latest pipeline agents no longer carry these older Developer Packs, causing an immediate MSB3644 build error.

Retarget the Application (Permanent Fix) Microsoft has officially ended support for .NET Framework 4.5.1 and 4.6.1. The best practice is to update the application’s source code to a supported version, such as 4.6.2 or 4.8.

  • Navigate to your Azure Repos and locate the .csproj files (e.g., PartsUnlimited.csproj and PartsUnlimited.Models.csproj).
  • Edit the files and look for the <TargetFrameworkVersion> XML tag.
  • Update the version string from v4.5.1 or v4.6.1 to a modern version like v4.8.
  • Commit and push the changes to your repository. The pipeline will automatically trigger and build successfully using the modern agent.

XML

<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>

The Chain Reaction

  • Unit Tests (PartsUnlimited.UnitTests.csproj): This project is still targeting v4.5.2. A v4.5.2 project cannot reference a newer v4.8 DLL, so it drops the reference entirely. Without that reference, the core classes (Controllers, Models, ViewModels, etc.) suddenly “vanish,” causing the massive wall of CS0234 and CS0246 missing namespace errors.
  • Selenium Tests (FabrikamFiber.SeleniumTests.csproj): This project is still explicitly asking for v4.6.1, which immediately throws the exact same MSB3644 missing Developer Pack error you saw initially.

The Fix

A Visual Studio Solution (.sln) requires all interdependent projects to run on compatible framework versions. You must update the remaining .csproj files to match your main project.

  1. Open test/PartsUnlimited.UnitTests/PartsUnlimited.UnitTests.csproj in your repository.
  2. Open test/FabrikamFiber.SeleniumTests/FabrikamFiber.SeleniumTests.csproj.
  3. Update the <TargetFrameworkVersion> XML tag in both files to v4.8.
  4. Commit and push the changes.

Once all projects in the solution are uniformly on v4.8, the MSBuild task will seamlessly compile the entire suite.

2. Fixing the Castle.Core & Moq Unit Test Crash

Upgrading to v4.8 creates a domino effect. The PartsUnlimited.UnitTests project will drop its references, throwing a wall of CS0234 missing namespace errors. Simultaneously, the Moq testing framework will crash with a System.IO.FileLoadException because it specifically expects Castle.Core v3.3.0.0, but the template includes v4.0.0.

To bypass the binding redirect failure, you must explicitly downgrade the Castle.Core package to exactly version 3.3.0 across the test project’s configuration files.

Here are the three files you need to update in the PartsUnlimited-aspnet45/test/PartsUnlimited.UnitTests/ directory:

  • packages.config: Change the Castle.Core package version string from "4.0.0" to "3.3.0".
  • PartsUnlimited.UnitTests.csproj: Locate the <Reference Include="Castle.Core..."> tag and update its <HintPath> to point to the 3.3.0 directory instead of the 4.0.0 directory (..\..\packages\Castle.Core.3.3.0\lib\net45\Castle.Core.dll).
  • app.config: Either delete the <dependentAssembly> block for Castle.Core entirely, or change the newVersion attribute in the binding redirect from "4.0.0.0" to "3.3.0.0".

Once you commit these version changes, NuGet will restore the exact 3.3.0 assembly that Moq requires, and the unit tests will successfully execute.

XML

<Reference Include="Castle.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
  <HintPath>..\..\packages\Castle.Core.3.3.0\lib\net45\Castle.Core.dll</HintPath>
</Reference>

3. Aligning YAML Pipeline Indentation

Azure Pipelines enforce strict YAML hierarchy rules. If your CI/CD pipeline fails to parse the deployment stages, ensure your pool, variables, and steps blocks are indented exactly two spaces underneath their respective job definitions, not floating at the root level.

YAML

stages:
- stage: Build
  jobs:
  - job: Build
    pool:
      vmImage: 'windows-latest'
    variables:
      solution: '**/*.sln'
    steps:
      - task: NuGetToolInstaller@1

5. Diagnosing Infinite Loading and 500 Errors

After the pipeline successfully deploys the zip package to your Azure App Service, browsing to the site often yields a generic 500 error or an infinite loading screen. By default, Azure App Services do not save application crash logs. You must enable diagnostic logging to see what is failing.

  • Navigate to your App Service in the Azure Portal.
  • Scroll to the Monitoring section and select App Service logs.
  • Toggle Application Logging (Filesystem) to On and set the Level to Error. Use the File System option for immediate troubleshooting, as it feeds directly into the real-time log stream without requiring an external Azure Storage account.
  • Toggle Web server logging to On and click Save.
  • Select Log stream from the left menu and refresh your website. Watch the terminal for real-time exceptions or SQL timeouts.

If the application crashes before the code even finishes loading, it will not appear in the standard log stream. Scroll down to Advanced Tools, launch the Kudu CMD terminal, navigate to the LogFiles folder, and inspect eventlog.xml for deep application pool crashes.

6. Exposing the Yellow Screen of Death (YSOD)

If you see a generic Runtime Error stating that custom error settings prevent details from being viewed, ASP.NET is actively hiding the stack trace for security reasons.

  • Open the App Service Editor (Preview) under the Development Tools menu.
  • Expand the WWWROOT directory and open Web.config.
  • Search for the <system.web> block and add or update the custom errors tag:

XML

<customErrors mode="Off" />
  • The editor saves automatically. Refresh your website tab to replace the security warning with the detailed stack trace.

7. Fixing the LocalDB Connection String Crash

With custom errors disabled, the PartsUnlimited template typically reveals a System.ComponentModel.Win32Exception tied to a SQL Network Interface error (Error 52). The legacy code is attempting to connect to a Local Database Runtime (LocalDB), which is not supported in Azure App Service environments.

You must explicitly inject your Azure SQL database credentials into the App Service:

  • Go to Environment variables (or Configuration) in your App Service settings.
  • Under the Connection strings tab, add a new entry named DefaultConnectionString (the code explicitly looks for this exact name).
  • Paste your full Azure SQL connection string: Server=tcp:<your-db-server>.database.windows.net,1433;Initial Catalog=<your-db-name>;User ID=<your-username>;Password=<your-password>;Encrypt=True;Connection Timeout=30;
  • Set the type to SQLAzure and click Save. The App Service will automatically restart.

8. Surviving the Serverless Auto-Pause (Cold Start)

Once the connection string is mapped, you might encounter one final crash: SqlException: Database 'partsunlimited-yaml' on server '...' is not currently available.

While this looks like a fatal routing error, it is usually a symptom of Azure’s Serverless compute architecture.

  • Serverless Auto-Pause: To save money, serverless Azure SQL databases pause during inactivity. The first web request to a sleeping database always throws this availability error while the compute resources spin back up. Wait 60 seconds and refresh the page.
  • Database Does Not Exist: Verify you actually created a blank database named partsunlimited-yaml on your SQL server so Entity Framework can execute its table migration scripts.
  • Firewall Blocks: Open your SQL Server’s Networking settings and ensure Allow Azure services and resources to access this server is checked so the App Service is not blocked at the perimeter.

If the exposed error is a System.Data.SqlClient.SqlException, you are likely hitting a Serverless auto-pause cold start. Azure SQL Databases on the Serverless compute tier pause during inactivity. The first web request times out while the compute spins back up. That happened in my case as well so wait for 60 seconds, and refresh the page to allow Entity Framework to execute its migrations.