System.Web Adapters for ASP.NET Core

repository·main·Indexed 18 days ago

https://github.com/dotnet/systemweb-adapters

A collection of adapters designed to facilitate incremental migration from legacy ASP.NET (System.Web) to ASP.NET Core by providing compatible API surfaces. It includes core API subsets, services for both ASP.NET Core and Framework applications, and shared abstractions. The project supports .NET 6.0, .NET Standard 2.0, and .NET Framework 4.7.2, enabling interoperability for session state, MachineKey security, and migration paths from WebForms to Blazor.

Tokens
12.1K
Snippets
32
Records
56
Agent score
61%

What's inside systemweb-adapters

  1. Overview of System.Web adapters for ASP.NET Core

    main

    The System.Web adapters project enables large-scale, incremental migration from ASP.NET (System.Web.dll based) to ASP.NET Core. It provides a bridge between the two frameworks by offering a subset of System.Web APIs backed by Microsoft.AspNetCore.Http types.

    The project consists of four main components:

    • Microsoft.AspNetCore.SystemWebAdapters: Provides the core API subset.
    • Microsoft.AspNetCore.SystemWebAdapters.CoreServices: Services for the ASP.NET Core application side.
    • Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices: Services for the ASP.NET Framework application side.
    • Microsoft.AspNetCore.SystemWebAdapters.Abstractions: Shared abstractions (like session serialization) used by both implementations.
  2. Explore migration samples for ASP.NET Framework to ASP.NET Core

    main

    The samples directory provides concrete examples of how to use the System.Web adapters to migrate applications from ASP.NET Framework to ASP.NET Core. All sample applications utilize a shared ClassLibrary project that demonstrates how to consume System.Web APIs through the adapters.

    Available sample scenarios include:

    • Pure ASP.NET Core with System.Web APIs: The CoreApp sample demonstrates an application that runs entirely on ASP.NET Core while still utilizing legacy System.Web APIs via the adapters.
    • Remote Authentication (Framework/Core Pairs): The RemoteApp/* samples demonstrate how an ASP.NET Core application can use remote authentication from an ASP.NET Framework application. This includes:
      • RemoteApp/Bearer: Uses bearer authentication. Requires an Azure B2C instance configured in appsettings.json.
      • RemoteApp/Forms: Uses forms-based authentication.
      • RemoteApp/Identity: Uses ASP.NET Framework Identity for authentication.
    • MachineKey Sharing: The MachineKey sample demonstrates how to share System.Web.Security.MachineKey calls between the ASP.NET Framework and ASP.NET Core environments.
  3. Emulate IHttpModule and HttpApplication in ASP.NET Core

    main

    The systemweb-adapters library provides an emulated pipeline for HttpApplication and IHttpModule that works on Kestrel or any other ASP.NET Core host. This is achieved by using middleware to invoke expected events at times that approximate the original ASP.NET pipeline.

    Note: This implementation is not tied to IIS and does not hook into IIS events even if running on IIS. It is intended as a stepping stone for migrating large, complex legacy modules that cannot be easily refactored into standard ASP.NET Core middleware.

    using System.Web;
    using ModulesLibrary;
    
    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddSystemWebAdapters()
        .AddHttpApplication<MyApp>(options =>
        {
            // Size of pool for HttpApplication instances. Should be what the expected concurrent requests will be
            options.PoolSize = 10;
    
            // Register a module by name
            options.RegisterModule<MyModule>("Module");
        });
    
    var app = builder.Build();
    
    app.UseSystemWebAdapters();
    
    app.Run();
    
    class MyApp : HttpApplication
    {
      protected void Application_Start() { ... }
      protected void Session_Start() { ... }
      protected void Begin_Request() { ... }
    }
    
    class MyModule : IHttpModule
    {
      public void Init(HttpApplication app) { ... }
      public void Dispose() { }
    }
  4. Understand the Writeable Remote Session Protocol (HTTP2 and SSL)

    main

    When HTTP2 and SSL are available, the Writeable session state protocol uses a single POST request that requires full-duplex streaming.

    1. ASP.NET Core sends a POST /session request.
    2. The ASP.NET framework retrieves the session from the Session Store and returns it to ASP.NET Core.
    3. ASP.NET Core runs the request and modifies the session state.
    4. ASP.NET Core streams the updated session state back to the framework.
    5. The framework persists the state to the Session Store and returns the persistence result as JSON.
  5. Understand the Readonly Remote Session Protocol

    main
    The Readonly session mode is used to retrieve session state from the legacy ASP.NET framework app without any locking mechanisms. It uses a single GET request to the framework to fetch the session state and can be closed immediately after the response is received. This mode is suitable for scenarios where session state does not need to be modified by the ASP.NET Core application.
  6. How the OWIN Pipeline Fork/Join mechanism works

    main

    The OWIN Pipeline uses a pipeline fork/join pattern to allow OWIN middleware to interleave its execution with the ASP.NET Core pipeline. This is necessary when running OWIN middleware within an emulated HttpApplication event lifecycle or when using OWIN middleware as an ASP.NET Core authentication handler.

    The mechanism involves two concurrent execution paths:

    1. Main Pipeline: The primary ASP.NET Core middleware pipeline or authentication handler.
    2. Forked Pipeline: The OWIN middleware pipeline.

    Execution Lifecycle

    1. Fork: The Main Pipeline initiates execution of the OWN pipeline (via RunForkedPipelineAsync), pausing its own progress.
    2. Forked Execution: The OWIN middleware (authentication, authorization, etc.) executes its logic.
    3. Join: The final piece of OWIN middleware calls JoinPipelineFork to yield control back to the Main Pipeline.
    4. Main Resumption: The Main Pipeline resumes, processes the results from the fork, and completes its work.
    5. Resume Forked (Cleanup): To ensure middleware cleanup occurs in the correct reverse order, the system schedules a final step (CompleteAsync) to run during the end-of-request finalization.
    sequenceDiagram
        participant Main as Main Pipeline
        participant Forked as Forked Pipeline
        
        Note over Main: Main pipeline executing
        Main->>Forked: Fork execution (RunForkedPipelineAsync)
        activate Forked
        Note over Main: ⏸️ Main pipeline pauses
        
        Note over Forked: Forked pipeline executes
        Note over Forked: (OWIN middleware, auth, etc.)
        Note over Forked: Work completes, ready to join
        
        Forked->>Main: Join (JoinPipelineFork)
        deactivate Forked
        Note over Forked: ⏸️ Forked pipeline pauses
        activate Main
        
        Note over Main: Main pipeline resumes
        Note over Main: Process results from fork
        Note over Main: Complete main work
        
        Main->>Forked: Resume forked (CompleteAsync)
        deactivate Main
        activate Forked
        
        Note over Forked: Forked pipeline resumes
        Note over Forked: Cleanup and finalization
        
        Forked-->>Main: Complete
        deactivate Forked
        
        Note over Main: Request continues
  7. OWIN Pipeline Fork/Join Scenarios

    main

    The fork/join mechanism is implemented to solve two specific integration challenges:

    1. Integrated Pipeline

    Used when running OWIN middleware within the emulated HttpApplication event lifecycle. This supports the ASP.NET Framework pattern where OWIN middleware is organized into stages (e.g., Authenticate, Authorize, AcquireState) that map to specific HttpApplication events (e.g., AuthenticateRequest, AuthorizeRequest). The pipeline must fork at stage boundaries to allow event handlers to execute and then join back to continue the OWIN flow.

    2. Authentication Handler

    Used when running OWIN authentication middleware (such as cookie authentication or OAuth) as an ASP.NET Core authentication handler. The mechanism allows the OWIN middleware to perform authentication and set the user principal, then return control to the ASP.NET Core authentication system to support both authentication and challenge/sign-out operations.

  8. How Visual Studio debugger attachment works for IIS Express in Aspire

    main

    When running IIS Express projects via Aspire, the debugger is not attached via the standard Aspire DCP (Distributed Control Plane) because DCP does not currently support attaching debuggers to arbitrary processes. Instead, a custom debugger attachment mechanism is used that automates Visual Studio through COM interop.

    The attachment process follows these steps:

    1. Detection: The extension monitors Aspire resource lifecycle events to detect when the IIS Express process starts.
    2. COM Discovery: It uses the Windows Running Object Table (ROT) to find active Visual Studio instances.
    3. Instance Matching: It matches the process ID of the current Aspire host to a running Visual Studio instance.
    4. DTE Automation: It uses the EnvDTE object model to programmatically command Visual Studio to attach.
    5. Process Attachment: It attaches the debugger to the IIS Express process using both native and managed debug engines.

    Technical Requirements for this mechanism:

    • Requires COM/ROT for VS instance discovery.
    • Uses EnvDTE (via custom interface definitions) for automation.
    • Operates on an STA Thread with a Message Pump to support COM interop with Visual Studio.
  9. Understand supported targets and runtime behavior

    main

    The adapters support several target frameworks with different behaviors:

    • .NET 6.0: Implements adapters against ASP.NET Core HttpContext. It provides conversions between ASP.NET Core HttpContext and the adapter's HttpContext (with caching to minimize GC impact). It also allows overriding functionality like session or caching via provided services.
    • .NET Standard 2.0: Acts as a reference assembly. Types do not have public constructors because they are constructed by the runtime (ASP.NET Core or Framework) based on the existing HttpContext.
    • .NET Framework 4.7.2: Type-forwards adapter classes to System.Web, allowing libraries built against .NET Standard 2.0 to run on .NET Framework instances.
  10. Understand HttpApplication lifetime and pooling

    main

    In the emulated pipeline, each request retrieves an HttpApplication instance from a pool. This instance holds event callbacks and state for the duration of the request.

    • Pooling: The library uses PooledObjectPolicy<HttpApplication> to manage instances. When a request exits the adapter middleware, the HttpApplication instance is returned to the pool and its assigned HttpContext is removed.
    • Customization: You can control the number of instances by setting HttpApplicationOptions.PoolSize. For advanced scenarios, you can provide a custom implementation of ObjectPool<HttpApplication> that utilizes the provided PooledObjectPolicy<HttpApplication> to override default pooling behavior.
    • Optimization: If no HttpApplication or IHttpModule types are registered, the emulated pipeline middleware is not added to the chain, avoiding unnecessary overhead.
  11. Handle AXD resource requests in WebForms

    main
    ASP.NET applications use .axd files to handle embedded resource requests (such as images, JavaScript, or CSS). To allow these files to be retrieved from a WebForms application during migration, use an AxdConstraint to ensure resources are injected into the client-side webpage and accessible on the server in a standard way.