dotnet / dotnet/systemweb-adapters

Proposal: AspNetCore HttpContext via FrameworkServices

Open
#682 0 comments 0 reactions 0 assignees View on GitHub
Needs: Triage :mag:
Dominant language
C#
Stars
384
Forks
76
Avg merge
2h 24m
Merged PRs (30d)
1

Description

## 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

2. 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

3. Create a DbContext class implementing `IDataProtectionKeyContext`

4. When configuring services use:
```cs
builder.Services.AddDbContext(optionsBuilder =>
optionsBuilder.UseSqlServer(builder.Configuration.GetConnectionString("MyDbContext"))
);
builder.Services.AddDataProtection().DisableAutomaticKeyGeneration().SetApplicationName("MyApplication").PersistKeysToDbContext();
var authenticationBuilder = builder.Services.AddAuthentication(IdentityConstants.ApplicationScheme);
authenticationBuilder.AddCookie(IdentityConstants.ApplicationScheme);
```
4. Configure the OWIN pipeline as below:
```cs
[assembly: OwinStartup(typeof(MyApp.Startup), "ConfigureOwin")]
public class Startup
{
public void ConfigureOwin(IAppBuilder app)
{
app.Use>();
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`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.