Skip to content

Add a singleton IHttpRuntime to abstract runtime data #185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions samples/ClassLibrary/RequestInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static void WriteRequestInfo(bool suppress)
using (var writer = new SimpleJsonWriter(context.Response))
{
writer.Write("VirtualDirectory", HttpRuntime.AppDomainAppVirtualPath);
writer.Write("VirtualDirectory", context.Request.ApplicationPath);
writer.Write("RawUrl", context.Request.RawUrl);
writer.Write("Path", context.Request.Path);
writer.Write("Length", context.Request.InputStream.Length);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.AspNetCore.SystemWebAdapters;

namespace Microsoft.Extensions.DependencyInjection;

internal static class HttpRuntimeFactory
{
public static IHttpRuntime Create()
{
if (NativeMethods.IsAspNetCoreModuleLoaded())
{
var config = NativeMethods.HttpGetApplicationProperties();

return new IISHttpRuntime(config);
}

return new DefaultHttpRuntime();
}

internal class DefaultHttpRuntime : IHttpRuntime
{
public string AppDomainAppVirtualPath => "/";
}

internal class IISHttpRuntime : IHttpRuntime
{
private readonly NativeMethods.IISConfigurationData _config;

public IISHttpRuntime(NativeMethods.IISConfigurationData config)
{
_config = config;
}

public string AppDomainAppVirtualPath => _config.pwzVirtualApplicationPath;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Web;
using System.Web.Caching;
using System.Web.Configuration;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SystemWebAdapters;
using Microsoft.AspNetCore.SystemWebAdapters.Mvc;

namespace Microsoft.Extensions.DependencyInjection;

Expand All @@ -17,6 +16,7 @@ public static class SystemWebAdaptersExtensions
public static ISystemWebAdapterBuilder AddSystemWebAdapters(this IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddSingleton<IHttpRuntime>(_ => HttpRuntimeFactory.Create());
services.AddSingleton<Cache>();
services.AddSingleton<BrowserCapabilitiesFactory>();
services.AddTransient<IStartupFilter, HttpContextStartupFilter>();
Expand All @@ -27,6 +27,8 @@ public static ISystemWebAdapterBuilder AddSystemWebAdapters(this IServiceCollect

public static void UseSystemWebAdapters(this IApplicationBuilder app)
{
HttpRuntime.Current = app.ApplicationServices.GetRequiredService<IHttpRuntime>();

app.UseMiddleware<DefaultCacheControlMiddleware>();
app.UseMiddleware<PreBufferRequestStreamMiddleware>();
app.UseMiddleware<SessionMiddleware>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.AspNetCore.SystemWebAdapters;

internal interface IHttpRuntime
{
string AppDomainAppVirtualPath { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ public partial class HttpResponseWrapper : System.Web.HttpResponseBase
public sealed partial class HttpRuntime
{
internal HttpRuntime() { }
public static string AppDomainAppVirtualPath { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public static string AppDomainAppVirtualPath { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
}
public partial class HttpServerUtility
{
Expand Down
3 changes: 1 addition & 2 deletions src/Microsoft.AspNetCore.SystemWebAdapters/HttpRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,7 @@ public bool IsLocal

public string AppRelativeCurrentExecutionFilePath => $"~{_request.Path.Value}";

[SuppressMessage("Performance", "CA1822:Mark members as static", Justification = Constants.ApiFromAspNet)]
public string ApplicationPath => HttpRuntime.AppDomainAppVirtualPath;
public string ApplicationPath => _request.HttpContext.RequestServices.GetRequiredService<IHttpRuntime>().AppDomainAppVirtualPath;

public Uri? UrlReferrer => TypedHeaders.Referer;

Expand Down
11 changes: 6 additions & 5 deletions src/Microsoft.AspNetCore.SystemWebAdapters/HttpRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ namespace System.Web;

public sealed class HttpRuntime
{
static HttpRuntime()
private static IHttpRuntime? _current;

internal static IHttpRuntime Current
{
AppDomainAppVirtualPath = NativeMethods.IsAspNetCoreModuleLoaded()
? NativeMethods.HttpGetApplicationProperties().pwzVirtualApplicationPath
: "/";
get => _current ?? throw new InvalidOperationException("HttpRuntime is not available in the current environment");
set => _current = value;
}

private HttpRuntime()
{
}

public static string AppDomainAppVirtualPath { get; }
public static string AppDomainAppVirtualPath => Current.AppDomainAppVirtualPath;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net;
Expand Down Expand Up @@ -417,14 +415,28 @@ public void AppRelativeCurrentExecutionFilePath()
[Fact]
public void ApplicationPath()
{
// Arrange
var appVirtualPath = _fixture.Create<string>();

var httpRuntime = new Mock<IHttpRuntime>();
httpRuntime.Setup(h => h.AppDomainAppVirtualPath).Returns(appVirtualPath);

var services = new Mock<IServiceProvider>();
services.Setup(s => s.GetService(typeof(IHttpRuntime))).Returns(httpRuntime.Object);

var coreContext = new Mock<HttpContextCore>();
coreContext.Setup(c => c.RequestServices).Returns(services.Object);

var coreRequest = new Mock<HttpRequestCore>();
coreRequest.Setup(c => c.HttpContext).Returns(coreContext.Object);

var request = new HttpRequest(coreRequest.Object);

// Act
var result = request.ApplicationPath;

// Assert
Assert.Equal(System.Web.HttpRuntime.AppDomainAppVirtualPath, result);
Assert.Equal(appVirtualPath, result);
}

[Fact]
Expand Down