Skip to content

Proposal: AspNetCore HttpContext via FrameworkServices #682

@EmperorArthur

Description

@EmperorArthur

Summary

Support using an AspNetCore HttpContext in .Net Framework 4.8, and using AspNetCore Middleware in the .Net Framework OWIN pipeline.

Motivation and goals

I have implemented a version of this in my company's code base and believe it would be a useful for others as well.

  • Enables transitioning .Net Framework classes to an AspNetCore HttpContext.
  • Allows said classes to be shared between a AspNetCore project and a Framework project without installing the adapter in the AspNetCore project.
  • Allows .NET Framework to use AspNetCore's authentication with minimal modification.

In scope

A list of major scenarios, perhaps in priority order.

  • Accessing an AspNetCore HttpClient via Dependency Injection.
  • Using .NET Core Middleware in an OWIN middleware pipeline.

Out of scope

Scenarios you explicitly want to exclude.

Risks / unknowns

How might developers misinterpret/misuse this? How might implementing it restrict us from other enhancements in the future? Also list any perf/security/correctness concerns.

  • Simple Implementation of an AspNetCore HttpContext relies on Microsoft.AspNetCore.Owin v2.3.10
  • Middleware adds an additional dependency on Microsoft.Owin
  • Adapter must be constructed for every request or a custom IHttpContextAccessor must be used.

My implementation used a custom IHttpContextAccessor, which uses IOwinContext.Environment. That solves the potential issue of threading causing the context to be unavailable, but feels a bit hackey.

The OWIN middleware adapter could be considered a separate feature but is a single class which makes things like the example below possible.

Examples

.NET Core Cookie Authentication in .NET Framework

This is an alternative to Microsoft.Owin.Security.Interop using AspNetCore modules directly. Example instructions are for using EF Core (v3) for data protection.

  1. Ensure the following dependencies exist in the project file:
  • Microsoft.Extensions.Identity.Core
  • Microsoft.AspNetCore.Identity
  • Microsoft.Data.SqlClient
  • Microsoft.EntityFrameworkCore (Version 3)
  • Microsoft.EntityFrameworkCore.SqlServer (Version 3)
  • Microsoft.Extensions.Identity.Core
  1. Copy the following files from Microsoft.AspNetCore.DataProtection.EntityFrameworkCore to a folder in the .NET Framework project:
  • DataProtectionKey.cs
  • EntityFrameworkCoreDataProtectionExtensions.cs
  • EntityFrameworkCoreXmlRepository.cs
  • IDataProtectionKeyContext.cs
  1. Create a DbContext class implementing IDataProtectionKeyContext

  2. When configuring services use:

builder.Services.AddDbContext<MyDbContext>(optionsBuilder =>
    optionsBuilder.UseSqlServer(builder.Configuration.GetConnectionString("MyDbContext"))
);
builder.Services.AddDataProtection().DisableAutomaticKeyGeneration().SetApplicationName("MyApplication").PersistKeysToDbContext<MyDbContext>();
var authenticationBuilder = builder.Services.AddAuthentication(IdentityConstants.ApplicationScheme);
authenticationBuilder.AddCookie(IdentityConstants.ApplicationScheme);
  1. Configure the OWIN pipeline as below:
[assembly: OwinStartup(typeof(MyApp.Startup), "ConfigureOwin")]
public class Startup
{
    public void ConfigureOwin(IAppBuilder app)
    {
        app.Use<NetCoreMiddlewareAdapter<AuthenticationMiddleware>>();
        app.UseStageMarker(PipelineStage.Authenticate);
    }
}

Detailed design

Most of the hard work can be done by using OwinFeatureCollection along with other default feature collections. However, there are several additional things which must be implemented.

  • ISession backed by HttpContextBase.Session.
  • IHttpResponseFeature.OnCompleted is needed by the RequestServicesFeature
    • This could be implemented in a different way.
  • IRequestCookiesFeature needs to be implemented with an OWIN backed IRequestCookieCollection
  • IResponseCookiesFeature needs to be implemented with an OWIN backed IResponseCookieCollection

I toyed with creating the individual features based on HttpContext.Current and the associated Worker, but this is much simpler of an approach.

I based the middleware adapter design on Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs: Triage 🔍Label added to new issues which need Triage

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions