ASP.NET Framework Migration to ASP.NET Core with YARP
Transitioning from ASP.NET Framework to ASP.NET Core was never simple, simply because of the way how ASP.NET Framework was created coupled to IIS, and how ASP.NET Core decoupled that dependency, introducing necessary breaking changes.
The migration
A new migration strategy is introduced with YARP. YARP is a reverse proxy used at Microsoft, that comes to bridge the challenging migration from ASP.NET Framework to ASP.NET Core.
Another reason this is now possible is because the new package Microsoft.AspNetCore.SystemAdapters.CoreServices
introduce adapters to the System.Web
library implementation of ASP.NET Framework, making it possible for ASP.NET Core to communicate with the legacy implementation.
Incremental changes allow the gradual transition of platforms, which was not possible before on ASP.NET.
where:
- Façade - becomes YARP
- Legacy - ASP.NET Framework
- Modern - ASP.NET Core
How it works
Requests arrive on ASP.NET Core, that hosts YARP, which validates the request endpoint based on its configuration mapping.
If route mapping is found for YARP, it forwards the request to ASP.NET Framework, which resolves the request.
If route mapping is not found for YARP, it then resolves the request on ASP.NET Core.
The example
An ASP.NET Framework 4.7.2 is used in this example, it contains a simple MVC page that makes a client JQuery AJAX request from the View to the Web API.
File: \Views\Dummy\Index.cshtml
<div class="row">
<div class="col-md-12">
<h2>This is a dummy example</h2>
<ul id="dummy-list"></ul>
</div>
</div>
@section scripts
{
<script>
$(document).ready(function () {
$.ajax({
url: "/api/values",
contentType: "application/json",
dataType: "json",
success: function (data) {
$.each(data, function (index, value) {
$("#dummy-list").append("<li>" + value + "</li>");
})
}
});
})
</script>
}
File: \Controllers\ValuesController.cs
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "dummy1", "dummy2" };
}
}
When it runs the following is displayed:
Migrating to ASP.NET Core
On Visual Studio 2022 install an Extension called Microsoft Project Migrations (Experimental).
After installation, it introduces some menu items for Migration, which automates project provisioning within the solution. Choose to Migrate Project:
Let's start the migration, by creating a new project:
The new project template to be created will be on .NET 7:
Note that for the new ASP.NET Core project, NuGet packages for YARP
, System.Web adapters
and YARP settings
will be automatically added by the tool:
After the project creation, this is what is available on appsettings.json
, containing the YARP settings:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ReverseProxy": {
"Routes": {
"fallbackRoute": {
"ClusterId": "fallbackCluster",
"Order": "2147483647",
"Match": {
"Path": "{**catch-all}"
}
}
},
"Clusters": {
"fallbackCluster": {
"Destinations": {}
}
}
}
}
and the ASP.NET Core project contains the following NuGet packages:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SystemWebAdapters.CoreServices" Version="1.0.0" />
<PackageReference Include="Yarp.ReverseProxy" Version="1.1.0" />
</ItemGroup>
</Project>
The Program.cs
initializes the ASP.NET Core. It is worth mentioning about the middlewares for SystemWebAdapters
and ReverseProxy
, injected to the Services:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSystemWebAdapters();
builder.Services.AddReverseProxy().LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSystemWebAdapters();
app.MapDefaultControllerRoute();
app.MapReverseProxy();
app.Run();
Before we run it, let's migrate the ValuesController
controller:
On the summary view of the controller, make sure to Migrate selection:
Note that the
ValuesController
is created on the new ASP.NET Core project.
To differentiate this ValuesController from the old one, modify the implementation to return a different string[]
result:
File: \Controllers\ValuesController.cs
[ApiController]
[Route("api/[controller]")]
public class ValuesController : ControllerBase
{
[HttpGet]
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "core1", "core2" };
}
}
When it runs now, the following is displayed:
This response comes from the new ASP.NET Core implementation, while the ASP.NET View is still coming from ASP.NET Framework. The gradual transition makes the migration painless, opening new possibilities for the migration of legacy solutions.
This example is available on PlayGoKids repository.