Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.SystemWebAdapters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace System.Web.Hosting;

internal sealed class HostingEnvironmentAccessor
{
private static readonly HttpContextAccessor _defaultHttpContextAccessor = new();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very familiar with this code, but how often is _accessor or _current null? If not too often, should we make this be lazily evaluated instead so as to only initialize it if needed? (might also not matter if instantiating an HttpContextAccessor is cheap)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how often is _accessor or _current null

good point - most of the time they are not null. It will only be if someone is running outside of a asp.net core host. I've changed it to just be a back up.

private static HostingEnvironmentAccessor? _current;

private readonly IOptions<SystemWebAdaptersOptions> _options;
private readonly IHttpContextAccessor? _accessor;

public HostingEnvironmentAccessor(IServiceProvider services, IOptions<SystemWebAdaptersOptions> options)
{
Services = services;
_accessor = services.GetService<IHttpContextAccessor>();
_options = options;
}

Expand All @@ -42,5 +47,10 @@ public static bool TryGet([MaybeNullWhen(false)] out HostingEnvironmentAccessor
return current is not null;
}

/// <summary>
/// Gets an <see cref="IHttpContextAccessor"/> that is either registered to the current hosting runtime or the default one via <see cref="HttpContextAccessor"/>.
/// </summary>
public static IHttpContextAccessor HttpContextAccessor => _current?._accessor ?? _defaultHttpContextAccessor;

internal SystemWebAdaptersOptions Options => _options.Value;
}
8 changes: 3 additions & 5 deletions src/Microsoft.AspNetCore.SystemWebAdapters/HttpContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
using System.Linq;
using System.Security.Principal;
using System.Web.Caching;
using System.Web.Hosting;
using System.Web.SessionState;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.AspNetCore.SystemWebAdapters;
using Microsoft.AspNetCore.SystemWebAdapters.Features;
Expand All @@ -20,8 +20,6 @@ namespace System.Web;

public class HttpContext : IServiceProvider
{
private static readonly HttpContextAccessor _accessor = new();

private HttpRequest? _request;
private HttpResponse? _response;
private HttpServerUtility? _server;
Expand All @@ -30,8 +28,8 @@ public class HttpContext : IServiceProvider

public static HttpContext? Current
{
get => _accessor.HttpContext?.AsSystemWeb();
set => _accessor.HttpContext = value?.AsAspNetCore();
get => HostingEnvironmentAccessor.HttpContextAccessor.HttpContext?.AsSystemWeb();
set => HostingEnvironmentAccessor.HttpContextAccessor.HttpContext = value?.AsAspNetCore();
}

internal HttpContext(HttpContextCore context)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Moq;
using Xunit;

namespace Microsoft.AspNetCore.SystemWebAdapters.CoreServices.Tests;

[Collection(nameof(SelfHostedTests))]
public class HttpContextCurrentTests
{
[Fact]
public void CurrentReturnsNullByDefault()
{
Assert.Null(HttpContext.Current);
}

[Fact]
public void SavesByDefaultToHttpContextAccessor()
{
// Arrange
var accessor = new HttpContextAccessor();
var context = new DefaultHttpContext();

// Act
HttpContext.Current = context;

// Assert
Assert.Same(accessor.HttpContext, context);
}

[Fact]
public async Task UsesIHttpContextAccessor()
{
// Arrange
var accessor = new Mock<IHttpContextAccessor>();
accessor.SetupAllProperties();

using var host = await new HostBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder
.UseTestServer()
.ConfigureServices(services =>
{
services.AddSingleton(accessor.Object);
services.AddSystemWebAdapters();
})
.Configure(app =>
{
});
})
.StartAsync();
var context = new DefaultHttpContext();

// Act
HttpContext.Current = context;

// Assert
Assert.Same(context, accessor.Object.HttpContext);
Assert.Null(new HttpContextAccessor().HttpContext);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Net.Http.Headers;
using Xunit;

using SameSiteMode = System.Web.SameSiteMode;

namespace Microsoft.AspNetCore.SystemWebAdapters.CoreServices.Tests;
Expand Down