Compartir a través de


Adaptadores System.Web

El caso de uso principal de los adaptadores en el repositorio dotnet/systemweb-adapters es ayudar a los desarrolladores que se han basado en los tipos System.Web dentro de sus bibliotecas de clases, ya que quieren pasar a ASP.NET Core.

Una característica importante de los adaptadores es que los adaptadores permiten usar la biblioteca tanto desde proyectos de ASP.NET Framework como de ASP.NET Core. La actualización de varias aplicaciones de ASP.NET Framework a ASP.NET Core suele implicar estados intermedios en los que no todas las aplicaciones se han actualizado completamente. Mediante el uso de los System.Web adaptadores, la biblioteca se puede usar tanto desde los autores de llamadas de ASP.NET Core como desde los autores de llamadas de ASP.NET Framework que no se han actualizado.

Echemos un vistazo a un ejemplo con los adaptadores que se mueven de .NET Framework a ASP.NET Core.

Paquetes

  • Microsoft.AspNetCore.SystemWebAdapters: Este paquete se usa en bibliotecas auxiliares y proporciona las API System.Web de las cuales puedes haber dependido, como HttpContext y otras. Este paquete tiene como destino .NET Standard 2.0, .NET Framework 4.5+, y .NET 5+.
  • Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices: este paquete solo tiene como destino .NET Framework y está pensado para proporcionar servicios a aplicaciones de ASP.NET Framework que pueden necesitar proporcionar migraciones incrementales. Por lo general, no se espera que se haga referencia a esto desde bibliotecas, sino desde las propias aplicaciones.
  • Microsoft.AspNetCore.SystemWebAdapters.CoreServices: este paquete solo tiene como destino .NET 6+ y está pensado para proporcionar servicios a aplicaciones de ASP.NET Core para configurar el comportamiento de las API de System.Web, así como participar en cualquier comportamiento para la migración incremental. Por lo general, no se espera que se haga referencia a esto desde bibliotecas, sino desde las propias aplicaciones.
  • Microsoft.AspNetCore.SystemWebAdapters.Abstractions: este paquete es un paquete auxiliar que proporciona abstracciones para los servicios usados por la aplicación ASP.NET Core y ASP.NET Framework, como la serialización de estado de sesión.

Conversión a System.Web.HttpContext

Para convertir entre las dos representaciones de HttpContext, puede hacer lo siguiente:

De HttpContext a HttpContext

  • Conversión implícita
  • HttpContext.AsSystemWeb()

De HttpContext a HttpContext

  • Conversión implícita
  • HttpContext.AsAspNetCore()

Ambos métodos utilizarán una representación en caché HttpContext durante la duración de una solicitud. Esto permite reescrituras dirigidas a HttpContext según sea necesario.

Ejemplo

ASP.NET Framework

Considere la posibilidad de un controlador que haga algo como:

public class SomeController : Controller
{
  public ActionResult Index()
  {
    SomeOtherClass.SomeMethod(HttpContext.Current);
  }
}

que luego tiene lógica en un ensamblado independiente pasando ese HttpContext de un lado a otro hasta que, finalmente, algunos métodos internos hacen alguna lógica en él, como:

public class Class2
{
  public bool PerformSomeCheck(HttpContext context)
  {
    return context.Request.Headers["SomeHeader"] == "ExpectedValue";
  }
}

ASP.NET Core

Para ejecutar la lógica anterior en ASP.NET Core, un desarrollador deberá agregar el Microsoft.AspNetCore.SystemWebAdapters paquete, lo que permitirá que los proyectos funcionen en ambas plataformas.

Las bibliotecas deben actualizarse para comprender los adaptadores, pero será tan sencillo como agregar el paquete y volver a compilar. Si son las únicas dependencias que tiene un sistema en System.Web.dll, las bibliotecas podrán tener como destino .NET Standard 2.0 para facilitar un proceso de creación más sencillo al migrar.

El controlador de ASP.NET Core tendrá ahora este aspecto:

public class SomeController : Controller
{
  [Route("/")]
  public IActionResult Index()
  {
    SomeOtherClass.SomeMethod(HttpContext);
  }
}

Tenga en cuenta que, dado que hay una propiedad HttpContext, pueden pasarlo a través, pero generalmente tiene el mismo aspecto. Con conversiones implícitas, HttpContext se puede convertir en el adaptador que se podría pasar a través de los niveles que usan el código de la misma manera.

Pruebas unitarias

Cuando se realizan pruebas unitarias en el código que utiliza los adaptadores de System.Web, hay algunas consideraciones especiales que debe tener en cuenta.

En la mayoría de los casos, no es necesario configurar componentes adicionales para ejecutar pruebas. Pero si el componente que se está probando usa HttpRuntime, podría ser necesario iniciar el SystemWebAdapters servicio, como se muestra en el ejemplo siguiente:

namespace TestProject1;

/// <summary>
/// This demonstrates an xUnit feature that ensures all tests
/// in classes marked with this collection are run sequentially.
/// </summary>
[CollectionDefinition(nameof(SystemWebAdaptersHostedTests),
    DisableParallelization = true)]
public class SystemWebAdaptersHostedTests
{
}
[Collection(nameof(SystemWebAdaptersHostedTests))]
public class RuntimeTests
{
    /// <summary>
    /// This method starts up a host in the background that
    /// makes it possible to initialize <see cref="HttpRuntime"/>
    /// and <see cref="HostingEnvironment"/> with values needed 
    /// for testing with the <paramref name="configure"/> option.
    /// </summary>
    /// <param name="configure">
    /// Configuration for the hosting and runtime options.
    /// </param>
    public static async Task<IDisposable> EnableRuntimeAsync(
        Action<SystemWebAdaptersOptions>? configure = null,
        CancellationToken token = default)
        => await new HostBuilder()
           .ConfigureWebHost(webBuilder =>
           {
               webBuilder
                   .UseTestServer()
                   .ConfigureServices(services =>
                   {
                       services.AddSystemWebAdapters();
                       if (configure is not null)
                       {
                           services.AddOptions
                               <SystemWebAdaptersOptions>()
                               .Configure(configure);
                       }
                   })
                   .Configure(app =>
                   {
                       // No need to configure pipeline for tests
                   });
           })
           .StartAsync(token);
    [Fact]
    public async Task RuntimeEnabled()
    {
        using (await EnableRuntimeAsync(options =>
            options.AppDomainAppPath = "path"))
        {
            Assert.True(HostingEnvironment.IsHosted);
            Assert.Equal("path", HttpRuntime.AppDomainAppPath);
        }
        Assert.False(HostingEnvironment.IsHosted);
    }
}

Las pruebas deben ejecutarse en secuencia, no en paralelo. En el ejemplo anterior se muestra cómo lograrlo estableciendo la opción de DisableParallelization XUnit en true. Esta configuración deshabilita la ejecución en paralelo para una recopilación de pruebas específica, lo que garantiza que las pruebas dentro de esa colección se ejecuten una después de la otra, sin simultaneidad.