Azure Cloud Services (Extended Support) Retires on 31 March 2027: Moving Web and Worker Roles

Microsoft deprecated Azure Cloud Services (extended support) on 31 March 2025 and retires it fully on 31 March 2027. If a line-of-business application of yours runs as web roles and worker roles, it has to be running somewhere else on Azure before that date. The retirement FAQ is blunt about the two questions everyone asks first: Microsoft "can't grant extension requests", and "there's no one-click migration tooling available."
From today, 3 October 2026, that leaves six months.
Who This Is For
The typical case: an ASP.NET application on .NET Framework, a web role in front and one or two worker roles processing queues behind it, built by an agency eight or ten years ago. The agency has often moved on, the application still runs order processing or a customer portal, and nobody has opened the .csdef file since the last migration.
To check whether you are affected, open the Azure portal and list resources of the type "Cloud services (extended support)". Microsoft's retirement notice links straight to that view. If it is empty, you are done.
This article is not about Cloud Services (classic), which was retired in 2024. If a vendor hosts the product for you, the migration is their job: ask for their date in writing. Everything below is for teams who own the code, or own it on paper and have to find someone who understands it.
Why This Is Harder Than the 2024 Move
Many companies moved to extended support in 2024, when classic was retired. That move was cheap by design. Microsoft's extended support overview says the .csdef, .cscfg and .cspkg files "are carried forward and there's no change in the formats", and that "No changes are required to runtime code". There was even an in-place migration. The same page suggested extended support for applications that are not evolving, because "it provides a quick migration path."
This time there is no like-for-like target. In Microsoft's words, Cloud Services "is about deploying applications as VMs. The code you write is tightly coupled to a VM instance". Your code knows it runs in a role. It reads configuration from the role, finds disk space through the role, gets certificates installed by the role, and runs setup scripts as an administrator before the role starts. All of that has to be replaced.
One more thing before you read the official guidance. Microsoft's retirement notice and FAQ name one destination, Service Fabric managed cluster. The overview page lists five, and Microsoft's own migration decision matrix compares seven. Service Fabric is a default, not a requirement, and for a lot of web roles it is the wrong one.
The Targets, and When Each Fits
Web and worker roles do not have to land in the same place. Pick a target per role.
App Service (Windows). The closest thing to a web role for an ASP.NET application. Windows instances come with the supported .NET Framework versions installed, so Web Forms and MVC 5 run without a rewrite. Worker roles can follow as WebJobs, which run "in the same instance as a web app" at no extra cost. The limit is the machine itself: Microsoft steers apps that need COM components, registry access or MSI installers to Managed Instance, so elevated startup tasks have nowhere to go on a standard plan.
App Service Managed Instance. Built for legacy Windows web apps. Per Microsoft's overview, it is "generally available for Windows web apps in select regions", limited to the Pv4 and Pmv4 plans, with .NET Framework 3.5 and 4.8 preinstalled and PowerShell install scripts that can register COM components, write registry keys, run MSI installers and configure IIS. That covers most of what elevated startup tasks did. The limits: web apps only (no WebJobs), no containers, Entra ID and managed identity only (no domain join, NTLM or Kerberos), and at the time of writing the only European region listed is North Europe.
Container Apps. Good for worker roles once they are on modern .NET: queue-driven scaling, scheduled and event-triggered jobs, scale to zero. But the container requirements say "Linux-based (linux/amd64) container images are required." Code on .NET Framework does not run there until it is ported.
Azure Kubernetes Service. Runs Windows Server containers in Windows node pools, so a .NET Framework role can be containerised and moved. The decision matrix rates both its migration complexity and its operational overhead as high. It fits if you already run Kubernetes, not as a first cluster for one legacy app.
Virtual Machine Scale Sets. The matrix calls it "Closer to Cloud Services model, offering easier lift-and-shift". You get the VM back, along with the patching, the image builds and the IIS setup that the role used to do for you.
Service Fabric managed cluster. Microsoft's named destination. Worker roles map onto it cleanly. Web roles often do not: Service Fabric "does not support IIS", and the conversion guide lists ASP.NET Web Forms as not supported, with conversion to ASP.NET Core MVC as the path. The Service Fabric migration guide adds that managed clusters "currently do not support containers", so an IIS-dependent app needs a traditional cluster, with more to operate.
Decision table
| Your role looks like this | Likely target | Where the work goes |
|---|---|---|
| ASP.NET Web Forms or MVC 5 web role, startup tasks trivial or none | App Service (Windows) | Configuration, certificates, deployment pipeline |
| Web role whose startup tasks install COM components, MSIs or registry keys | App Service Managed Instance | Rewriting startup tasks as install scripts; checking region and plan |
| .NET Framework worker role polling a queue, modest load | WebJob next to the web app | Replacing RoleEntryPoint with a console host |
| Worker role you are willing to port to modern .NET | Container Apps | The port itself, then a container image |
| Many roles, and a team that already runs Kubernetes | AKS with Windows node pools | Images, cluster operations |
| Heavy native dependencies, no appetite for code change | VM Scale Sets | OS patching and image maintenance, permanently |
| Worker-heavy system, web tier already on ASP.NET Core | Service Fabric managed cluster | Learning the platform; no IIS, no containers |
What Changes in the Code
Search the solution for Microsoft.WindowsAzure.ServiceRuntime. Every file that imports it is on the list.
RoleEntryPoint
A worker role is a class that inherits RoleEntryPoint and overrides OnStart, Run and OnStop. If Run returns, the instance recycles. Service Fabric folds all three into a single RunAsync that should stop "when the RunAsync method's CancellationToken is signaled". On App Service or in a container, the same logic becomes a console application or a hosted background service with a loop and a cancellation token.
The part people miss is shutdown. OnStop gave you a moment to finish the message in hand. Make sure the new host passes a cancellation signal through, and that a message abandoned mid-processing is safe to process twice.
Web roles often have one too, typically WebRole.cs. If its OnStart does anything (IIS tweaks, cache warm-up), find out what before deleting it.
RoleEnvironment
RoleEnvironment.GetConfigurationSettingValue("Key") reads settings from the .cscfg. Nothing outside Cloud Services provides it. Before moving anything, wrap every call in one small configuration interface, then point that interface at app settings, environment variables or Key Vault on the new host. It is the cheapest change in the project and it makes the rest testable on a laptop.
Three other uses to look for:
RoleEnvironment.Changed, which applied configuration changes without a restart. Service Fabric has an equivalent event. Elsewhere, assume a setting change restarts the process and test what that does to work in flight.RoleEnvironment.CurrentRoleInstanceused to elect one instance for scheduled work. Triggered WebJobs run on a single instance; continuous ones run on all instances unless restricted. Decide explicitly.RoleEnvironment.IsAvailableandIsEmulatedbranches. These separate the "cloud" path from the "local" path, and one of them is about to become dead code.
.cscfg and .csdef
The .cscfg holds per-environment settings, instance counts and certificate thumbprints. The .csdef holds endpoints, VM size, local storage, startup tasks, certificate stores and sometimes several IIS sites inside one web role. Go through both line by line and write down where each entry lives afterwards: an app setting, a Key Vault reference, infrastructure code, or nowhere. Internal endpoints that let roles call each other directly need a replacement, either a service address or a queue.
Certificates
Extended support already forced certificates into Key Vault, so that part of the 2024 work pays off. What changes is how code finds them. A .csdef installs certificates into a named store, often LocalMachine. On Windows App Service, the WEBSITE_LOAD_CERTIFICATES setting makes them available in Current User\My. Code that opens the LocalMachine store finds nothing, and the first call that needs the certificate fails. On Linux containers, load it from Key Vault at startup instead.
Startup tasks
Open Startup.cmd. This is where the surprises live, typically run with executionContext="elevated": fonts for PDF generation, a COM component, an IIS rewrite module, a registry change for TLS. Each line has three possible fates: no longer needed, moved into an install script on Managed Instance, or baked into a container or VM image.
Local storage
A LocalStorage resource in the .csdef, read through RoleEnvironment.GetLocalResource, gave each instance scratch disk. Use the platform temp directory for genuine scratch files. Anything that must outlive a restart, including files someone assumed were permanent, goes to Blob Storage.
Web Forms
This is the decision that drives the rest. Web Forms is built on System.Web and has no ASP.NET Core version, so moving a Web Forms application to Service Fabric or Container Apps means rewriting its user interface. App Service, Managed Instance, a Windows container or a scale set can all run it unchanged. Move it as it is and make modernisation a separate project with its own budget. A UI rewrite does not belong on the critical path of a shutdown date.
The rest
VIP swap between two cloud services becomes deployment slots on App Service or revisions on Container Apps. Logs sent through the diagnostics (WAD) extension need a new destination, usually Application Insights. Standard App Service and Container Apps offer no remote desktop; Managed Instance allows it through Azure Bastion, for diagnostics only.
A Six-Month Plan
Working back from 31 March 2027, with December holidays in the middle.
October: inventory and target choice. List every extended support deployment. For each role, record the .NET Framework version, Web Forms or MVC, every RoleEnvironment call, startup task, local storage resource, certificate and endpoint. Then check the uncomfortable part: can you build the deployed package from the source you have? With agency-built systems the answer is sometimes no, and October is the month to find out. Choose a target per role.
November: one role, end to end. Add the configuration wrapper, write the target environment as infrastructure code, and get one role (usually the simplest worker) running in a test environment with logs, certificates and a pipeline.
December and January: port the rest. Replace entry points, startup tasks and local storage. Load-test a staging environment with production-like data: a WebJob or container may not match the throughput of a dedicated role VM.
February: parallel running. Run the new environment against real traffic. For workers sharing a queue with the old roles, either make processing idempotent first or stop the old workers before starting the new ones.
Early March: cut over. Switch DNS with time to spare. Keep the old deployment stopped but intact for a week or two, then delete it. Do not schedule the cutover for the last week of March: a failed cutover then has no second attempt.
If you are starting in January instead, drop the modernisation entirely. Pick the target that needs the least code change (App Service, Managed Instance or scale sets), move, and refactor afterwards.
What Is Not Clear
Microsoft says the service will be "fully retired" and that migration is needed "to avoid service disruption". The pages we read do not say what happens to a deployment still running on 1 April 2027. Do not plan on finding out. Managed Instance regions and plans are also likely to change over the coming months, so confirm them when you decide, not from this article.
Where to Get Help
We take over applications other people built, work out how they run, and move them: the inventory, the target per role, the RoleEnvironment and startup task changes, and the cutover. Our legacy system maintenance work covers .NET Framework and Web Forms; if your own team is doing the migration and needs extra hands, see staff augmentation.
If you have a Cloud Services deployment and a date six months away, write to office@c9group.dev.