APIs Upgrade from .NET 4.x to .NET 8

 

Executive Summary

Applications are running on old technologies need to go through transition into latest technologies. Running core applications using obsolete technologies can pose big risks, and limit to achieve high availability, reliability, and scalability. These limitation and others hinder the organization’s ability to innovate, scale and maintain a secure application environment.

This proposal enable application to migrate from .NET framework 4.x to .NET 8 aims to improve performance, reduces security VITs and container ready, ensuring the longevity and scalability of the application. As part of the strategy, it is proposed to create a new code repository (this will help to migrate from old repository to new for example GitHub) to help developers establish a more organized version control history, making it easier to track changes, manage branches and handle pull requests effectively. It also provides a clear distinction between the old and new codebases, reducing the risk of accidental dependencies on legacy code and simplifying the deprecation process of the legacy application version. Deploying an application upgraded version side-by-side with legacy version can be a highly effective strategy for minimizing risk and ensuring a smooth transition. This approach allows to compare both versions in a production like environment and provides a fallback option if issues arise with the new version.

Background

Applications built using the technology stack and framework which now old or obsolete, are challenge to upgrade using new technologies because of business continuity. However, the team is currently encountering several challenges due to the outdated technology and frameworks, such as issues with scalability, observability, security vulnerabilities, unit testing and high operation cost, among others.

Proposed Solution

This paper is focused on various aspects of performance, maintainability, security and future readiness. Below are the key objective:

·       Remove all the dependencies on the legacy .NET Framework​ 4.x. The use of .Net 8 will allow application to run in containerized environments, and subsequent support the container deployment strategy.

·       Reduce vulnerabilities due to outdated technologies.

·       Reduce technical debt and make future upgrades simpler: Below are the few examples.

o   The application is running in 32 bits. With the .NET 8 upgrade we can run the application in 64-bit, which will enhance performance.

o   Application lacks a dependency injection framework, limiting the team’s ability to write true unit tests. Dependency injection is a built-in part of .NET 8, which will help improve product quality.

Measurable Outcomes

Known Industry Data:

 

Security Vulnerabilities

Critical Vulnerabilities should be identified and remediated within 30 days.

Security patches should be applied within 7 days of the release

Developer Productivity

Build times should be less than 15 minutes.

Deployment frequency should be biweekly

Performance

For standard operation, response times for API endpoints should be less than 100 milliseconds.

Should handle 1000 requests per second.

CPU Usage should be less than 60% under normal load.

Memory usage should be less than 65% of available RAM under typical operation

 

This document proposes Canary Deployment approach to migrate legacy code from .NET Framework 4.x to .NET 8. This approach aims to minimize risk, reduce downtime and ensure continuous delivery of new features/improvements by deploy the upgraded version alongside the legacy version.

Code Repository

It is proposed to create new code repository and .NET 8 instead of using existing repository, below are some of the advantages: 

·       Clean Slate for Development: Developers can focus on code upgrade without the distraction of dealing with legacy code issues, leading to more efficient development cycles. 

·       Improve Version ControlBy starting a new repository, developers can establish a more organized version control history, making it easier to track changes, manage branches and handle pull requests effectively. 

·       Clear Separation of Concerns: It provides a clear distinction between the old and new codebases, reducing the risk of accidental dependencies on legacy code and simplifying the deprecation process of the legacy application version. 

·       Risk Management: By isolating the new codebase, the risk of introducing bugs or vulnerabilities into the legacy application during the upgrade process is minimized. 

Upgrade Tools and Resources 

.NET Upgrade Assistant can be used to upgrade application legacy code.

.NET Upgrade Assistant: Command line tool/VS Extension that helps upgrade .NET Framework application to .NET 8. 

Installation: Its available as a Visual Studio extension or as command line tool.

Upgrade Process 

Following are steps involved in upgrading from .NET 4.x Framework to .NET 8:

1.     Preparation Phase

1.     Initial Planning and Assessment: Evaluate the current state of the application, identify potential risks, create mitigation plans and establish rollback procedures. Communicate the development plan to all stake holders.

2.     Development and Testing:

1.     Initial Setup: Identify the team member who are responsible of upgrade the application from legacy solution to .NET 8, compile it successfully. To achieve this following team, need to perform the following:

1.     Update Solution/Project Files.

2.     Update Dependencies.

3.     Refactor startup project. 

2.     Code Changes: In this stage development team will join the initiative to resolve any runtime error/issues and deploy the application in DEV environment. In this stage team will focus on issues which may require other team support or work around to make the application work. Following are few example of such cases:

1.     Refactoring of WCF Call.

2.     Create proxy service to handle legacy integration which not compatible with .NET 8 such as MSMQ.

3.     Configuration management (AppSettings and System.Web, runtime tags). 

4.     Refactor logging code.

5.     Dependency Injection Framework Refactor.

6.     Integration Test Migration.

7.     Update Configuration and Settings (encrypt the config file).

3.     DevOps Changes: Update CI/CD pipeline to use .NET 8 for building and deploying .NET 8 application. 

4.     Configure Monitoring and Logging tools: Work with operation team to configure monitoring tools for the application .NET 8 version. For better support, it is recommended to create separate account for application .NET 8 version. This will provide a clear distinction between the old and new application.

5.     Testing and Validation: In this stage team will conduct unit and integration testing and begin UAT with clients. Below are the testing techniques team will use:

1.     Automated Tests: Run application integration tests suite using application upgraded .NET 8 API endpoint to ensure that the application behaves as expected. 

2.     Manual Testing: Conduct extensive manual testing to catch any issues not covered by automated integration tests. 

6.     Build Infrastructure: These are the three approaches we can adopt:

1.     Build new Servers: This approach requires lot of co-ordination between different team for example, provision servers, open firewall, updating DevOps pipeline. Due to time constraint this may not work well for us.

2.     Re-purpose existing Servers: With this approach you can initially repurpose few of servers to host application .NET 8 version. As you gain confidence in .NET 8 version, more servers can shift from legacy to upgraded version. In the end all servers will be repurposed to upgraded application version.

3.     Use both Legacy and New application on same Servers: In this approach both legacy and new application version will be hosted on same servers. This technique may create some hardware resource (CPU, Memory) conflict.


My recommendation is to “Re-purpose Existing Server” approach as this provide clear distinction between the old and new application but in the same time quick to provision.

2.     Deployment Phase
Deploying an application upgraded version side-by-side with legacy version can be a highly effective strategy for minimizing risk and ensuring a smooth transition. This approach allows to compare both versions in a production like environment and provides a fallback option if issues arise with the new version.

1.     Canary Deployment:

1.     Setup: Deploy the upgraded version alongside the legacy version.

2.     Partial Traffic: Route a small percentage of user traffic to the upgraded version while the majority continues to use the legacy version.

3.     Monitoring: Monitoring the behavior of the canary release closely. if successful, gradually increase the percentage of traffic directed to the upgraded version.

2.     Implementation
Gradually increase the percentage of traffic to the upgraded version as confidence grows. Once the upgraded version is stable and performs well, transition all traffic to it.

1.     Load Balancer Configuration

1.     Load Balancer: Use application Load balancer to manage traffic distribution between the two versions.

2.     Routing Rules: Configure routing rules to direct traffic based on deployment strategy.

3.     Rollback Plan:

If issues arise with the upgraded version, immediately route all traffic back to the legacy version. The rollback involves only a change to the ALB routing and can be performed without system downtime.

3.     Code Sync Process/Strategy: 
To support the business continuity, development of new API or bug fixes will not be freeze at anytime. Application .NET 8 team will make sure to sync the code from legacy to .NET code repository. As we make the progress there will be following phases of the upgrade that requires different Code sync strategy:

1.     Pre Deployment: After code fork from legacy and upgraded to .NET 8 version, .NET 8 team is responsible to sync the code from the legacy after every application release cycle.

 

2.     Post Deployment: After Upgraded code deployed in production, application developer who creates a PR in legacy repo is also responsible for PR creation in the new repo. This is the most challenging phase of the code sync as it create too much work for developers.

3.     Legacy Freeze: After all traffic transits to application .NET 8 version, .NET 8 repository will become primary repository and all the bug fixes and enhancement activities will shift to .NET 8 repository. At this point developers will create all PRs in .NET 8 code repository and manually merge the code to legacy code repository, just to keep both repository in sync to support the situation where we need to rollback to legacy.
After all traffic is shifted to application .NET 8 version, it is preferred to fix the issue in .NET 8 version instead of legacy repo, as we consider that the probability of rolling back to legacy after moving to .NET 8 version is less.

 

Measuring Impact

To ensure the success and effectiveness of the incremental upgrade to .NET 8 and modularization, it is essential to measure the impact throughout the migration process. Below are key metrics and methodologies for evaluating the impact:

Performance Metrics

       Application performance:

o   Response times: Measure the average response time for key application functions before and after each migration phase.

o   Throughput: Monitor the number of requests handled per second.

·       Resource Utilization: Track CPU, memory, and disk usage to assess any changes in resource efficiency.

·       Startup time : Compare application startup times before and after migration

·       Load testing: Conduct load testing to determine how the application performs under high traffic conditions and compare results across migration phase.

Quality Metrics

       Error rates: Monitor error rates and types of errors occurring in the application, aiming for a reduction as the migration progresses.

·       Bug counts: Track the number of reported bugs and issues in each phase, targeting a decrease as stability improves.

·       Test coverage: Ensure comprehensive test coverage for all migrated components and track improvements over time.

Quality Metrics

       User feedback: Work with the product team to collect user feedback and satisfaction scores though surveys and support channels comparing results before and after upgrades.

·       API response times: Measure API response time and aim for reductions as migration progresses.

·       Application downtime: Track and downtime or disruptions experienced during the migration and aim to minimize these occurrences.

Development and Operation Metrics

     Development time: Measure the time taken to migrate each module or component and compare against estimates to improve planning accuracy.

2.     Deployment frequency: Track the frequency of development and updates during the migration process, aiming to maintain or increase deployment cadence.

3.     Code quality: Use static code analysis tools (such as SonarQube) to measure code quality metrics and adherence to coding standards.

4.     Integration and regression testing: Monitor the number of successful and failed integration and regression tests to ensure continuous stability.

Methodologies for Measuring Impact

     Baseline comparison: Establish a baseline for all metrices before starting the migration and compare these baselines to post migration data to measure improvements.

2.     A/B testing: For APIs, conduct testing to compare client experience between legacy API and migrated API versions.

3.     Monitoring and logging: Improve comprehensive monitoring and logging to capture real-time data on application performance, errors and resource utilization.

4.     Performance benchmarks: Conduct regular performance benchmarking tests to measure and compare the performance of the application throughout the migration process.

 

By systematically measuring these metrics and employing these methodologies, we can accurately assess the impact of the incremental upgrade to .NET 8 and modularization, ensuring that each phase delivers tangible improvements, and that the overall migration achieves its intended goals.

Security, Privacy, Risks

1.     Parallel Development

The legacy code base is continuously changing. Since the .NET 8 upgrade will occur using a separate codebase, there is a risk of legacy changes to being posted to the .NET 8 codebase and vice versa. To minimize this risk, you can plan to have regular synchronization between the two codebases.

2.     Resource Allocation

As teams may already working on other priorities, getting resources fully dedicated to.NET 8 upgrades can be challenging.

3.     Dependency on other Teams

For the .NET 8 upgrade, you may need support from other teams, Any delays from these teams could impact the delivery schedule.

4.     API Compatibility

Although most .NET and third-party libraries support both .Net Framework 4.x and .Net 8, there is still the possibility that some legacy libraries don’t support .Net 8. The team will need to identify potential incompatibilities during migration and remediate them.

5.     Platform Dependencies

Platform dependencies are another big challenge with migration projects from .NET Framework to .NET 8. Most dependencies are caused by a reliance on OS-specific features or CPU configurations (32 vs 64 bit binary support). Platform-specific dependencies in applications built by .NET framework may vary, but problems commonly arise with third-party components or system-level integration points such as Windows Registry access or COM interop calls.

One way of solving this challenge is by doing away with the dependencies altogether, especially if they are unnecessary for core functionality. However, if the team cannot replace or do away with certain dependencies, other options will have to be explored.

6.     Code Refactoring 

Upgrading to .NET 8 from .NET Framework 4.x comes with new behavior patterns, causing differences between the APIs of the two frameworks. For example, .NET 8 might lack certain classes or methods, requiring the team to rewrite the sections of the code that apply to them. In other words, refactoring the existing code is necessary. 

7.     Testing Strategy 

A typical migration project requires extensive testing to validate the application’s functionality and stability when deployed across different platforms. In addition to leveraging the existing tests, developers might also need to conduct compatibility testing, especially if they are going to identify and remediate platform-specific issues emanating from the migration process. 

Alternative Approaches

Below are pros and cons of .NET and .netstandard2 approaches:

.NET 8 Upgrade

This proposal enables application to migrate from .NET framework 4.x to .NET 8 aims to improve performance, reduces security VITs and GP container ready, ensuring the longevity and scalability of the application. As part of the strategy, it is proposed to create a new code repository to help developers establish a more organized version control history, making it easier to track changes, manage branches and handle pull requests effectively. It also provides a clear distinction between the old and new codebases, reducing the risk of accidental dependencies on legacy code and simplifying the deprecation process of the legacy application version. Deploying an application upgraded version side-by-side with legacy version can be a highly effective strategy for minimizing risk and ensuring a smooth transition. This approach allows to compare both versions in a production like environment and provides a fallback option if issues arise with the new version. Below are the pros and cons of this approach:

Pros:

·       Can be delivered in fast pace.

·       With Canary deployment, rollback will be easy. Using application load balancer's weighted configuration, traffic can be shifted back to the legacy system without requiring any changes to the legacy or client application.

·       The Application Code will be ready for Containerization.

·       Application performance will be improved by upgrading to .NET 8 and running it on 64-bit IIS process.

·       Can statically validate whether the code is truly portable.

·       With .NET 8, the team can eliminate the use of .NET Framework 4.x VITs.

Cons:

·       For short period, two versions of the Application will need to be supported until the full rollout of .NET 8 is complete.

·       Code merge from the legacy repository to new .NET 8 repository.

·       Legacy code history will not be available in the .NET 8 repository.

 

.NETStandard2 Incremental

A proposal for upgrading application with the intention of reducing risk, time to delivery, and a future path for further development. This would be accomplished in incremental steps against the existing codebase. This would be accomplished by converting dependent libraries to .NET Standard 2.0 and then swapping out the primary project with a new .NET 8 API. Following that, dependent libraries can be upgraded or replaced over time to .NET 8+. Below are the pros and cons of .netstand2 incremental approach

Pros:

·       Can be worked on in parallel with any alternative approaches.

·       Code can be upgraded and tested iteratively and on a regular basis.

·       Only one version of application needs to be supported.

·       Code history is preserved.

Cons:

·       As per the current process, full regression and load testing are required whenever project's target framework is changed.

·       New VITs may be introduce due to refencing older versions of NuGet packages with. netstandard2.

·       Application requires another upgrade cycle for .NET 8.

·       The rollback strategy involves reverting to the previous version, which necessitates downtime, adding complexity, especially if the release includes database schema changes.

·       As upgrades and regular enhancement/bug fixes occur in the same repository/solution, there is a possibility that developers may step into each other’s code, potentially leading to merge issues.

 

Proposing upgrade application from .NET Framework 4.x  to .NET 8. Here are reasons why .NET 8 is preferred over .NET Standard2.0: 

·       Latest Language Features: .NET 8 supports the newest C# language features, improving developer productivity and code quality. 

·       Performance Improvement: .NET 8 includes numerous performance enhancements, making application faster and more efficient. 

·       Long Term Support: .NET 8 is cross-platform, allows to run application on Windows and Linux. This opens the opportunity to host application in container. 

·       NuGet Package .NET Standard2.0 Support: In some cases, it is observed that latest NuGet package not compatible with .netstandard and need to use previous version to make it work which may create VITs problem (for example - System.ServiceModel dlls, FeatureToggle doesn't have support in .net standard 2.0) 

·       Duplicate Effort: Need to go though another upgrade process to upgrade to .NET 8 from .NET standard. For example, Implementations of System.Web and System.Configuration is different in both frameworks.

·       Testing Scope: If we update the same solution with .NET Standard every incremental release needs full regression test as the dlls are used across the functionalities. 

Conclusion

In Conclusion, upgrading as application from .NET Framework 4.x to .NET 8 offers significant benefits in terms of performance, security and modern development practices. The migration process may involve substantial changes, such as upgrading dependencies, refactoring code and ensuring compatibility with new APIs. However, these efforts are rewarded with enhanced scalability, access to the latest .NET ecosystem features and long-term support from Microsoft. The upgraded future proofs the application, enabling it to leverage the power of modern tools, cloud-native architectures, and improved development workflows, making it more resilient and adaptable to future technological advancements.