Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -10,6 +10,6 @@ internal static class RegexConstraintSupport
// until the context switch flows to the runtime.
// This value gets updated by the linker when the app is trimmed, so the code will always be removed from
// webassembly unless the switch is enabled.
public static bool IsEnabled =>
public static bool IsEnabled { get; } =
AppContext.TryGetSwitch("Microsoft.AspNetCore.Components.Routing.RegexConstraintSupport", out var enabled) && enabled;
Comment thread
Youssef1313 marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<Reference Include="Microsoft.AspNetCore.Components" />
<Reference Include="Microsoft.Extensions.DependencyInjection" />
<Reference Include="Microsoft.Extensions.Diagnostics.Testing" />
<Reference Include="Microsoft.DotNet.RemoteExecutor" />
</ItemGroup>

<ItemGroup>
Expand Down
21 changes: 11 additions & 10 deletions src/Components/Components/test/RendererTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Microsoft.AspNetCore.Components.RenderTree;
using Microsoft.AspNetCore.Components.Test.Helpers;
using Microsoft.AspNetCore.InternalTesting;
using Microsoft.DotNet.RemoteExecutor;
using Microsoft.Extensions.Logging.Abstractions;

namespace Microsoft.AspNetCore.Components.Test;
Expand Down Expand Up @@ -4981,13 +4982,18 @@ public async Task DisposeAsyncCallsComponentDisposeAsyncOnSyncContext()
Assert.True(wasOnSyncContext);
}

[Fact]
public async Task NoHotReloadListenersAreRegistered_WhenHotReloadIsDisabled()
[ConditionalFact]
[RemoteExecutionSupported]
public void NoHotReloadListenersAreRegistered_WhenHotReloadIsDisabled()
{
// Arrange
try
var options = new RemoteInvokeOptions();
options.RuntimeConfigurationOptions.Add("System.Reflection.Metadata.MetadataUpdater.IsSupported", "false");

using var remoteHandle = RemoteExecutor.Invoke(static async () =>
{
// Set the switch before any code triggers HotReloadManager type initialization.
AppContext.SetSwitch("System.Reflection.Metadata.MetadataUpdater.IsSupported", false);

await using var renderer = new TestRenderer();
var hotReloadManager = new HotReloadManager();
renderer.HotReloadManager = hotReloadManager;
Expand All @@ -4998,17 +5004,12 @@ public async Task NoHotReloadListenersAreRegistered_WhenHotReloadIsDisabled()
builder.CloseElement();
});

// Act
var componentId = renderer.AssignRootComponentId(component);
component.TriggerRender();
Assert.False(hotReloadManager.IsSubscribedTo);

await renderer.DisposeAsync();
}
finally
{
AppContext.SetSwitch("System.Reflection.Metadata.MetadataUpdater.IsSupported", true);
}
}, options);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ internal sealed class HttpNavigationManager : NavigationManager, IHostEnvironmen
{
private const string _disableThrowNavigationException = "Microsoft.AspNetCore.Components.Endpoints.NavigationManager.DisableThrowNavigationException";

[FeatureSwitchDefinition(_disableThrowNavigationException)]
private static bool _throwNavigationException =>
private static readonly bool s_throwNavigationException =
!AppContext.TryGetSwitch(_disableThrowNavigationException, out var switchValue) || !switchValue;

[FeatureSwitchDefinition(_disableThrowNavigationException)]
private static bool _throwNavigationException => s_throwNavigationException;

private Func<string, Task>? _onNavigateTo;

void IHostEnvironmentNavigationManager.Initialize(string baseUri, string uri) => Initialize(baseUri, uri);
Expand Down
115 changes: 63 additions & 52 deletions src/Components/Endpoints/test/EndpointHtmlRendererTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.InternalTesting;
using Microsoft.DotNet.RemoteExecutor;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.FileProviders;
Expand Down Expand Up @@ -982,62 +983,72 @@ public async Task Rendering_ComponentWithJsInteropThrows()
exception.Message);
}

[Theory]
[ConditionalTheory]
[RemoteExecutionSupported]
[InlineData(true)]
[InlineData(false)]
public async Task UriHelperRedirect_ThrowsInvalidOperationException_WhenResponseHasAlreadyStarted(bool allowException)
public void UriHelperRedirect_ThrowsInvalidOperationException_WhenResponseHasAlreadyStarted(bool allowException)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Components.Endpoints.NavigationManager.DisableThrowNavigationException", isEnabled: !allowException);
// Arrange
var ctx = new DefaultHttpContext();
ctx.Request.Scheme = "http";
ctx.Request.Host = new HostString("localhost");
ctx.Request.PathBase = "/base";
ctx.Request.Path = "/path";
ctx.Request.QueryString = new QueryString("?query=value");
ctx.Response.Body = new MemoryStream();
var responseMock = new Mock<IHttpResponseFeature>();
responseMock.Setup(r => r.HasStarted).Returns(true);
ctx.Features.Set(responseMock.Object);
var httpContext = GetHttpContext(ctx);
string redirectUri = "http://localhost/redirect";
var options = new RemoteInvokeOptions();
options.RuntimeConfigurationOptions.Add(
"Microsoft.AspNetCore.Components.Endpoints.NavigationManager.DisableThrowNavigationException",
(!allowException).ToString().ToLowerInvariant());

// Act
if (allowException)
using var remoteHandle = RemoteExecutor.Invoke(static async (allowExceptionStr) =>
{
var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () => await renderer.PrerenderComponentAsync(
httpContext,
typeof(RedirectComponent),
null,
ParameterView.FromDictionary(new Dictionary<string, object>
{
{ "RedirectUri", redirectUri }
})));

Assert.Equal("A navigation command was attempted during prerendering after the server already started sending the response. " +
"Navigation commands can not be issued during server-side prerendering after the response from the server has started. Applications must buffer the" +
"response and avoid using features like FlushAsync() before all components on the page have been rendered to prevent failed navigation commands.",
exception.Message);
}
else
{
await renderer.PrerenderComponentAsync(
httpContext,
typeof(RedirectComponent),
null,
ParameterView.FromDictionary(new Dictionary<string, object>
{
{ "RedirectUri", redirectUri }
}));
// read the custom element from the response body
httpContext.Response.Body.Position = 0;
var reader = new StreamReader(httpContext.Response.Body);
var output = await reader.ReadToEndAsync();

// Assert that the output contains expected navigation instructions.
var pattern = "^<blazor-ssr><template type=\"redirection\".*>.*<\\/template><blazor-ssr-end><\\/blazor-ssr-end><\\/blazor-ssr>$";
Assert.Matches(pattern, output);
}
var allowException = bool.Parse(allowExceptionStr);
var services = CreateDefaultServiceCollection().BuildServiceProvider();
var renderer = new TestEndpointHtmlRenderer(services, NullLoggerFactory.Instance);

var ctx = new DefaultHttpContext();
ctx.Request.Scheme = "http";
ctx.Request.Host = new HostString("localhost");
ctx.Request.PathBase = "/base";
ctx.Request.Path = "/path";
ctx.Request.QueryString = new QueryString("?query=value");
ctx.Response.Body = new MemoryStream();
ctx.RequestServices = services;
var responseMock = new Mock<IHttpResponseFeature>();
responseMock.Setup(r => r.HasStarted).Returns(true);
ctx.Features.Set(responseMock.Object);
string redirectUri = "http://localhost/redirect";

if (allowException)
{
var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () => await renderer.PrerenderComponentAsync(
ctx,
typeof(RedirectComponent),
null,
ParameterView.FromDictionary(new Dictionary<string, object>
{
{ "RedirectUri", redirectUri }
})));

Assert.Equal("A navigation command was attempted during prerendering after the server already started sending the response. " +
"Navigation commands can not be issued during server-side prerendering after the response from the server has started. Applications must buffer the" +
"response and avoid using features like FlushAsync() before all components on the page have been rendered to prevent failed navigation commands.",
exception.Message);
}
else
{
await renderer.PrerenderComponentAsync(
ctx,
typeof(RedirectComponent),
null,
ParameterView.FromDictionary(new Dictionary<string, object>
{
{ "RedirectUri", redirectUri }
}));
// read the custom element from the response body
ctx.Response.Body.Position = 0;
var reader = new StreamReader(ctx.Response.Body);
var output = await reader.ReadToEndAsync();

// Assert that the output contains expected navigation instructions.
var pattern = "^<blazor-ssr><template type=\"redirection\".*>.*<\\/template><blazor-ssr-end><\\/blazor-ssr-end><\\/blazor-ssr>$";
Assert.Matches(pattern, output);
}
}, allowException.ToString(), options);
}

[Fact]
Expand Down Expand Up @@ -1343,7 +1354,7 @@ public async Task RenderMode_CanRenderInteractiveComponents()
lines[0] = AssertAndStripBrowserConfiguration(lines[0]);
var serverMarkerMatch = Regex.Match(lines[0], PrerenderedComponentPattern);
var serverNonPrerenderedMarkerMatch = Regex.Match(lines[1], ComponentPattern);

var webAssemblyMarkerMatch = Regex.Match(lines[2], PrerenderedComponentPattern);
var webAssemblyNonPrerenderedMarkerMatch = Regex.Match(lines[3], ComponentPattern);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<Reference Include="Microsoft.AspNetCore.Routing" />
<Reference Include="Microsoft.AspNetCore.Routing.Abstractions" />
<Reference Include="Microsoft.Extensions.Hosting" />
<Reference Include="Microsoft.DotNet.RemoteExecutor" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;

namespace Microsoft.AspNetCore.Components.QuickGrid;

internal static class QuickGridFeatureFlags
{
internal static bool EnableUrlBasedQuickGridNavigationAndSorting =>
!AppContext.TryGetSwitch("Microsoft.AspNetCore.Components.QuickGrid.EnableUrlBasedQuickGridNavigationAndSorting", out var isEnabled) || isEnabled;
private const string EnableUrlBasedNavigationSwitchName =
"Microsoft.AspNetCore.Components.QuickGrid.EnableUrlBasedQuickGridNavigationAndSorting";

#pragma warning disable IDE0044
private static bool s_enableUrlBasedQuickGridNavigationAndSorting =
!AppContext.TryGetSwitch(EnableUrlBasedNavigationSwitchName, out var isEnabled) || isEnabled;
#pragma warning restore IDE0044

[FeatureSwitchDefinition(EnableUrlBasedNavigationSwitchName)]
internal static bool EnableUrlBasedQuickGridNavigationAndSorting => s_enableUrlBasedQuickGridNavigationAndSorting;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal sealed partial class RemoteNavigationManager : NavigationManager, IHost
private const string _disableThrowNavigationException = "Microsoft.AspNetCore.Components.Endpoints.NavigationManager.DisableThrowNavigationException";

[FeatureSwitchDefinition(_disableThrowNavigationException)]
private static bool _throwNavigationException =>
private static bool _throwNavigationException { get; } =
!AppContext.TryGetSwitch(_disableThrowNavigationException, out var switchValue) || !switchValue;
private Func<string, Task>? _onNavigateTo;

Expand Down
6 changes: 4 additions & 2 deletions src/Components/Shared/src/HotReloadManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ internal sealed class HotReloadManager
{
public static readonly HotReloadManager Default = new();

[FeatureSwitchDefinition("System.Reflection.Metadata.MetadataUpdater.IsSupported")]
internal static bool IsSupported =>
private static readonly bool s_isSupported =
AppContext.TryGetSwitch("System.Reflection.Metadata.MetadataUpdater.IsSupported", out bool isSupported) ? isSupported : true;

[FeatureSwitchDefinition("System.Reflection.Metadata.MetadataUpdater.IsSupported")]
internal static bool IsSupported => s_isSupported;

/// <summary>
/// Gets a value that determines if OnDeltaApplied is subscribed to.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,15 @@ public RazorComponentEndpointsStartup(IConfiguration configuration)
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
if (Configuration.GetValue<bool>("DisableUrlDrivenNavigation"))
{
AppContext.SetSwitch("Microsoft.AspNetCore.Components.QuickGrid.EnableUrlBasedQuickGridNavigationAndSorting", false);
}
else
{
AppContext.SetSwitch("Microsoft.AspNetCore.Components.QuickGrid.EnableUrlBasedQuickGridNavigationAndSorting", true);
}
var enableUrlNavigation = !Configuration.GetValue<bool>("DisableUrlDrivenNavigation");
AppContext.SetSwitch("Microsoft.AspNetCore.Components.QuickGrid.EnableUrlBasedQuickGridNavigationAndSorting", enableUrlNavigation);

// Also update the cached field in QuickGridFeatureFlags, since it captures the AppContext
// switch value once at static initialization and won't see subsequent AppContext changes.
var featureFlagsType = typeof(Microsoft.AspNetCore.Components.QuickGrid.QuickGrid<>).Assembly
.GetType("Microsoft.AspNetCore.Components.QuickGrid.QuickGridFeatureFlags");
featureFlagsType?.GetField("s_enableUrlBasedQuickGridNavigationAndSorting", BindingFlags.Static | BindingFlags.NonPublic)
?.SetValue(null, enableUrlNavigation);

services.AddValidation();

Expand Down
5 changes: 4 additions & 1 deletion src/Identity/Core/src/SignInManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public class SignInManager<TUser> where TUser : class
private const string PasskeyOperationKey = "PasskeyOperation";
private const string PasskeyStateKey = "PasskeyState";

private static readonly bool AlwaysResetLockoutOnSuccess =
AppContext.TryGetSwitch("Microsoft.AspNetCore.Identity.CheckPasswordSignInAlwaysResetLockoutOnSuccess", out var enabled) && enabled;

private readonly IHttpContextAccessor _contextAccessor;
private readonly IAuthenticationSchemeProvider _schemes;
private readonly IUserConfirmation<TUser> _confirmation;
Expand Down Expand Up @@ -475,7 +478,7 @@ private async Task<SignInResult> CheckPasswordSignInCoreAsync(TUser user, string

if (await UserManager.CheckPasswordAsync(user, password))
{
var alwaysLockout = AppContext.TryGetSwitch("Microsoft.AspNetCore.Identity.CheckPasswordSignInAlwaysResetLockoutOnSuccess", out var enabled) && enabled;
var alwaysLockout = AlwaysResetLockoutOnSuccess;
// Only reset the lockout when not in quirks mode if either TFA is not enabled or the client is remembered for TFA.
if (alwaysLockout || !await IsTwoFactorEnabledAsync(user) || await IsTwoFactorClientRememberedAsync(user))
{
Expand Down
3 changes: 2 additions & 1 deletion src/Mvc/Mvc.ViewFeatures/src/DefaultEditorTemplates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal static class DefaultEditorTemplates
{
private const string HtmlAttributeKey = "htmlAttributes";
private const string UsePasswordValue = "Switch.Microsoft.AspNetCore.Mvc.UsePasswordValue";
private static readonly bool _usePasswordValue = AppContext.TryGetSwitch(UsePasswordValue, out var enabled) && enabled;

public static IHtmlContent BooleanTemplate(IHtmlHelper htmlHelper)
{
Expand Down Expand Up @@ -312,7 +313,7 @@ public static IHtmlContent ObjectTemplate(IHtmlHelper htmlHelper)
public static IHtmlContent PasswordTemplate(IHtmlHelper htmlHelper)
{
object value = null;
if (AppContext.TryGetSwitch(UsePasswordValue, out var usePasswordValue) && usePasswordValue)
if (_usePasswordValue)
{
value = htmlHelper.ViewData.TemplateInfo.FormattedModelValue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class AuthorizationMiddleware
{
// AppContext switch used to control whether HttpContext or endpoint is passed as a resource to AuthZ
private const string SuppressUseHttpContextAsAuthorizationResource = "Microsoft.AspNetCore.Authorization.SuppressUseHttpContextAsAuthorizationResource";
private static readonly bool _suppressUseHttpContextAsAuthorizationResource = AppContext.TryGetSwitch(SuppressUseHttpContextAsAuthorizationResource, out var enabled) && enabled;

// Property key is used by Endpoint routing to determine if Authorization has run
private const string AuthorizationMiddlewareInvokedWithEndpointKey = "__AuthorizationMiddlewareWithEndpointInvoked";
Expand Down Expand Up @@ -181,7 +182,7 @@ public async Task Invoke(HttpContext context)
}

object? resource;
if (AppContext.TryGetSwitch(SuppressUseHttpContextAsAuthorizationResource, out var useEndpointAsResource) && useEndpointAsResource)
if (_suppressUseHttpContextAsAuthorizationResource)
{
resource = endpoint;
}
Expand Down
Loading
Loading