Containers

Migrating and modernizing Windows Communication Foundation (WCF) workloads onto AWS container services

Introduction

Windows Communication Foundation (WCF) is a framework created by Microsoft in 2008 for building service-oriented architecture (SOA) applications. It provides a set of libraries for building web services, using different network protocols to send and receive data between service endpoints.

With the introduction of .NET Core in 2016 and the emergence of microservices, our customers have gradually adopted other highly interoperable, cross-platform, language-agnostic, and high-performance solutions for building web services, such as REST APIs on ASP.NET Web API and Google Remote Procedure Call (gRPC). However, it is common that many organizations still run their legacy WCF-based applications on Windows platforms. In addition, many of our customers adopt container strategies and wish to containerize their legacy WCF workloads to run on AWS container services so that they can fully realize the benefits of containerization—increased operational efficiency, reduced infrastructure cost, increased development and deployment agility with standardized builds, and deployment processes across their organization.

This blog post discusses the background of WCF, .NET, and a few other alternatives to WCF in .NET. It also recommends different solutions and strategies for migrating and modernizing WCF workloads onto AWS container services.

Background

WCF was introduced in .NET Framework 3.5, providing a set of libraries for building SOA web services. WCF workloads follow client-server architecture using two primary network communication protocols: HTTP and NetTCP, a high-performance, TCP-based network protocol introduced specifically in WCF. NetTCP-based WCF workloads require that both the client and server are implemented in .NET Framework. In 2016, WCF was removed from Microsoft’s strategic, cross-platform successor of .NET Framework, .NET Core, which is now called .NET. In this blog post, we will use .NET Core and .NET interchangeably.

REST APIs and gRPC

Since WCF is not supported in .NET, our customers are encouraged to use ASP.NET Web API (REST APIs) or gRPC to build new web services in .NET. gRPC is cross platform, lightweight, highly performant for building web services, and officially supported in .NET. In some cases, gRPC-based applications provide even higher performance, with the flexibility of being language agnostic, when compared to NetTCP-based WCF workloads.

Core WCF

In 2019, .NET Foundation sponsored an open-source project called Core WCF, which was later jointly supported by AWS, to provide a port of WCF to .NET. To be able to use WCF in .NET, you need to first port your existing .NET Framework applications to .NET and replace the WCF libraries with the comparable libraries available in Core WCF. At the time of writing this blog post, certain features from WCF might not be supported in Core WCF. Hence, we recommend that you check out the official announcements from the Core WCF team.

Microservices and containers

In recent years, we have seen a tremendous shift in adopting microservices architecture. In addition, our customers usually use container services to help with deploying, running, and managing their microservices. Many of our customers would also like to run or modernize their legacy workloads to be able to run on a container service.

With WCF in particular, we are often asked by our customers for guidance in modernizing their WCF workloads, specifically, how to run their WCF workloads on AWS container services. With  .NET, Core WCF, other technologies such as REST APIs on ASP.NET Web API, and gRPC, there are plenty of options to migrate or modernize their WCF workloads onto a container service. You can replatform or refactor your workloads to be hosted on AWS by utilizing one or more of the strategies mentioned in the 6 strategies for Migrating Applications to the Cloud blog post. This is described in the following sections.

Replatforming

You can Dockerize your WCF workloads using one of the Microsoft Windows base images and deploy the workloads to one of the AWS container services. Compared to the refactoring approach, this approach generally involves fewer changes to the application and, hence, decreased time to market. It also maintains compatibility, so it reduces any potential impacts to the existing workloads. However, some changes might be required to ensure all current features are working as expected in a container environment. You need to also spend efforts in preparing the container. This approach is most suitable for the following workloads:

  • Mission-critical workloads where stability and minimal modification to the application are desired
  • NetTCP workloads where refactoring and modernizing to .NET using gRPC or Core WCF involves a higher degree of complexity and effort in refactoring the WCF backend and, likely, its clients
  • Workloads that cannot change API contract due to restrictions from client’s implementation

We advise you to conduct thorough application code assessments that might not work or might require changes to work in Windows containers, such as reading and writing permissions to the Windows Registry; local file storage; related domain-joined security features, such as Windows authentication; in-memory local session data; and so on. Extra efforts might also be required, such as installing and configuring the tools and software that are currently required in the virtual machines (VMs) to the containers. These changes and extra efforts can vary depending on the current setup. It’s important to take them into account to estimate the work required for this approach.

You can also use AWS App2Container to reduce the complexity and manual efforts in containerizing your IIS-hosted WCF workloads. For NetTCP workloads, you need to use a Network Load Balancer (NLB). While with HTTP workloads, both an Application Load Balancer and a Network Load Balancer are suitable. The following base images can be used to Dockerize the workloads:

  • Windows Server Core
  • Windows

The containerized workloads are supported on the following services:

  • Amazon Elastic Container Service (Amazon ECS) with Amazon Elastic Compute Cloud (Amazon EC2)
  • Amazon ECS with AWS Fargate
  • Amazon Elastic Kubernetes Service (Amazon EKS)

Note: Currently Amazon EKS with Fargate and AWS Elastic Beanstalk does not support Windows containers.

Customers adopting this approach should also consider the containers’ size in their architectural and operational considerations. Sizeable Windows container base images can cause prolonged startup time and could impact the time taken in scaling events, such as scaling out. Building Windows-based containers requires using Docker on Windows, which is equally important; thus, having a continuous integration and continuous delivery (CI/CD) system that is capable of building Windows containers is required.

Refactoring

In this approach, we recommend refactoring the WCF workloads to cross-platform .NET workloads. Refactoring is most suitable for you if you have a strategy and are willing to spend extra effort to refactor and containerize the workloads to .NET running on Linux or Windows containers. By refactoring to .NET, you can enjoy a wide range of benefits:

  • Long-term support—.NET is open source and strategically supported by Microsoft. Both REST APIs on ASP.NET Web AP and gRPC are proven, widely adopted technologies. Core WCF is also backed by .NET Foundation and AWS.
  • Increased resource efficiency and performance—.NET workloads work across platforms and can run on small-footprint, highly performant, and widely supported Linux and Windows (Nano Server) containers. Unlike Windows Server Core and Windows base images, Nano Server base image is significantly smaller in size. You can now run more containers on the same provisioned compute resource. Workloads can also respond to scaling events quicker compared to running on full Windows base images, increasing agility as well as operational resiliency.
  • Cost savings—Costs are reduced thanks to improved resource usage efficiency, reduced operational overheads, license-free Linux containers, and shared platform costs. At scale, running on license-free Linux containers can bring savings by avoiding the license-included cost on Amazon EC2 Windows instances.
  • Wider range of options for choosing a container service—There are more options because the workloads can run on either Linux or Windows containers.

Our customers generally have two options in this approach:

  • Move away from WCF—Port the applications to .NET and modernize the applications to ASP.NET Web API or gRPC technologies. Under this option, customers are able to benefit from these highly interoperable and cross-platform technologies. This option involves refactoring WCF workloads with the HTTP protocol to ASP.NET Web API. In addition, customers can also port their NetTCP WCF applications to gRPC on .NET. gRPC provides comparable performance and, in most cases, better performance, with NetTCP. It is required that customers spend efforts in both porting the current applications to .NET and rewriting the application to adopt gRPC or ASP.NET Web API. It also requires contract changes and breaking compatibility, hence involving additional efforts in changing the client’s implementation due to the new API contracts.
  • Stay with WCF—Port the applications to .NET but still maintain the WCF API contracts by using Core WCF. This option is ideal for customers who are willing to adopt .NET but not willing to spend further efforts refactoring and making significant changes to the applications. It not only provides the benefits of running on .NET but also reduces the potential impacts to the current workloads by not breaking or minimally breaking changes to the API contracts. However, it is important to note that Core WCF is still under active development and currently does not support all the bindings, transports, and security models currently available in WCF.

You can also use Porting Assistant for .NET to reduce the complexity and manual effort in porting your WCF workloads to .NET. Recently, .NET Porting Assistant has added support for porting WCF workloads to Core WCF.

The following table summarizes the high-level steps required for both replatforming and refactoring.

Steps Replatform Refactor to REST API or gRPC Refactor with Core WCF
Containerize apps
Remove/rewrite non-containers-friendly code
Refactor to .NET
Refactor to Core WCF
Refactor to ASP.NET Core or gRPC
Client changes (due to contract change) Possible
Testing effort Medium High Medium–high

The modernized workloads can be hosted in both Windows and Linux containers on the following platforms:

  • Elastic Beanstalk (Linux containers)
  • Amazon ECS with Amazon EC2
  • Amazon ECS with Fargate
  • Amazon EKS
  • Amazon EKS with Fargate (Linux containers)
  • AWS App Runner (Linux containers)

Note: Currently Amazon EKS with Fargate and Elastic Beanstalk does not support Windows containers.

Examples

In the following examples, we will replatform and refactor the server-side application from a WCF-based system to Amazon ECS with Fargate. The system follows the traditional client-server architecture, and both server and clients use WCF on .NET Framework 4.8.

Architecture diagram for the WCF-based system in which both client and server are implemented using .NET Framework 4.8. The client and server communicate through port 80 (HTTP) and port 808 (NetTCP) protocol.

Prerequisites

The examples require the following tools:

  • AWS Command Line Interface (AWS CLI) with default Region set
  • Docker Desktop
  • .NET Framework 4.8 SDK and MSBuild
  • .NET 6
  • PowerShell
  • AWS Copilot CLI (which you should ensure is widely available through the PATH system variable)
  • jq

Replatforming

In this example, we containerize the WCF server-side application into an Amazon ECS cluster and host it using Fargate. The following is the new architecture.

Architecture diagram for the WCF replatforming example. The WCF server is now Dockerized using Windows base image and hosted in Amazon ECS with Fargate behind load balancers listening on port 80 and 808. The client remains the same.

Dockerfile

Here is the Dockerfile for this solution with the following notes:

  • Windows Server Core 2019 LTSC is selected as it is currently supported by Amazon ECS with Fargate.
  • Two ports are exposed on the container—80 (HTTP) and 808 (NetTCP).

Deploy ECS cluster

Since this is a Windows base image, switching to Windows containers mode on Docker Desktop is required. Create a new Amazon ECS cluster using the following commands:

git clone https://github.com/aws-samples/containerization-options-for-wcf 
cd containerization-options-for-wcf/src/Replatforming
mkdir copilot/replatforming
@'
name: replatforming
type: Load Balanced Web Service

http:
  path: "/"
  healthcheck:
    path: "/CalculatorService"
    success_codes: "200"
    healthy_threshold: 3
    unhealthy_threshold: 5
    interval: 15s
    timeout: 10s
    grace_period: 45s

nlb:
  port: 808/tcp
  target_port: 808

image:
  build:
    dockerfile: Dockerfile
  port: 80

cpu: 4096
memory: 8192
count: 2
platform: windows/x86_64
environments:
  test:
    count: 2
    deployment:
      rolling: "recreate"
'@ | Out-File ./copilot/replatforming/manifest.yml
copilot app init wcfreplatforming
copilot init --name replatforming --type "Load Balanced Web Service" --deploy

Once the stack is created, let’s inspect the Docker container size:

docker images --format "{{.Repository}}: {{.Size}}" "*/wcfreplatforming/replatforming:latest"

The size should be around 8.25 GB:

444455556666.dkr.ecr.ap-southeast-2.amazonaws.com/wcfreplatforming/replatforming: 8.25GB

Testing

Build the client application:

$LB_HTTP_DNS = (copilot svc show --app wcfreplatforming --name replatforming --json | jq -r .routes[0].url).Split(" ")[0]
$LB_NETTCP_DNS = (copilot svc show --app wcfreplatforming --name replatforming --json | jq -r .routes[0].url).Split(" ")[2]
cd ../CurrentWorkload/Client
MsBuild.exe Client/Client.csproj /property:Configuration=Release

Test the HTTP protocol:

.\Client\bin\Release\Client.exe $LB_HTTP_DNS


Test the NetTCP protocol:

.\Client\bin\Release\Client.exe $LB_NETTCP_DNS

Clean up

Use the following command to clean up the resource:

cd ..\..\Replatforming
copilot app delete

There are a few implications due to large container size:

  • When using Amazon ECS or Amazon EKS with Amazon EC2, ensure that underlying storage has enough free space to spin up new container instances as required.
  • Ensure the container image repository is closer to the compute (Amazon EC2 instance or Fargate), ideally using Amazon Elastic Container Registry (Amazon ECR) in the same Region to reduce download time. This in turn reduces the startup time and data transfer charges. You can implement cache strategy to avoid expensive operations on the disk and shorten the container startup time.
  • Containers startup time must be taken into consideration from an architecture and operation point of view. With a spiky workload, it is important to ensure the number of running containers is able to handle the spiky traffic. You should also consider using time-based auto scaling to handle predictable traffic.

Refactoring using Core WCF

In this example, we will modernize the server-side application to .NET 6 using Porting Assistant for .NET and Core WCF. Thanks to Core WCF, all the API contracts remain the same; thus, the client application will not be changed. To find out about using Porting Assistant for .NET, please refer to the blog post on Modernizing legacy WCF applications to Core WCF using Porting Assistant for .NET. The following is the architecture for this example.

Architecture diagram for the WCF refactoring example. The WCF server is modernized to .NET 6 and runs on Linux-based container image. The server is hosted in Amazon ECS with Fargate behind load balancers listening on port 80 and 808. The client remains the same.

Dockerfile

Here is the Dockerfile for the modernized solution with the following notes:

  • We use Microsoft’s standard images; however, customers can use other base images with .NET 6 SDK and runtime installed.
  • Two ports are exposed on the container: 80 (HTTP) and 808 (NetTCP).
  • These base images are Linux-based; hence, switching to Linux containers is required on Docker Desktop.

Deploy ECS cluster

Create a new ECS cluster using the following commands:

git clone https://github.com/aws-samples/containerization-options-for-wcf 
cd containerization-options-for-wcf/src/Refactoring
mkdir copilot/refactoring
@'
name: refactoring
type: Load Balanced Web Service

http:
  path: "/"
  healthcheck:
    path: "/health-check"
    success_codes: "200"
    healthy_threshold: 3
    unhealthy_threshold: 5
    interval: 15s
    timeout: 10s
    grace_period: 45s

nlb:
  port: 808/tcp
  target_port: 808

image:
  build:
    dockerfile: Dockerfile
  port: 80

cpu: 4096
memory: 8192
count: 2
environments:
  test:
    count: 2
    deployment:
      rolling: "recreate"
'@ | Out-File ./copilot/refactoring/manifest.yml
copilot app init wcfrefactoring
copilot init --name refactoring --type "Load Balanced Web Service" --deploy

Inspect the size of the container image:

docker images --format "{{.Repository}}: {{.Size}}" "*/wcfrefactoring/refactoring:latest"

It is about 117 MB compared to 8.2 GB in the previous example.

444455556666.dkr.ecr.ap-southeast-2.amazonaws.com/wcfrefactoring/refactoring: 117MB

Testing

Build the client application:

$LB_HTTP_DNS = (copilot svc show --app wcfrefactoring --name refactoring --json | jq -r .routes[0].url).Split(" ")[0]
$LB_NETTCP_DNS = (copilot svc show --app wcfrefactoring --name refactoring --json | jq -r .routes[0].url).Split(" ")[2]
cd ../CurrentWorkload/Client
MsBuild.exe Client/Client.csproj /property:Configuration=Release

Test the HTTP protocol:

.\Client\bin\Release\Client.exe $LB_HTTP_DNS


Test the NetTCP protocol:

.\Client\bin\Release\Client.exe $LB_NETTCP_DNS


In this example, we deployed a modernized WCF workload to Amazon ECS with Fargate. The workload is license-free, is significantly smaller in size, has a quicker startup time, and is highly optimized, hence requiring smaller compute and storage requirements while offering better overall performance.

Clean up

Use the following command to clean up the resource:

cd ..\..\Refactoring
copilot app delete

Conclusion

In this blog, we walk you through different options for migrating and modernizing WCF workloads onto one of the AWS container services. Replatforming is more suitable for workloads that require minimal application changes and maintain backward compatibility. Our customers can also benefit from refactoring the workloads onto a modern .NET using ASP.NET Web API, gRPC, or Core WCF. The refactored workloads work across platforms and can be run on both Linux and Windows containers, hence enabling customers to fully realize the benefits of containerization.

Customers are also encouraged to check out the following resources: