|
22 | 22 | using Microsoft.AspNetCore.Http; |
23 | 23 | using Microsoft.AspNetCore.Http.Features; |
24 | 24 | using Microsoft.AspNetCore.InternalTesting; |
| 25 | +using Microsoft.DotNet.RemoteExecutor; |
25 | 26 | using Microsoft.Extensions.DependencyInjection; |
26 | 27 | using Microsoft.Extensions.DependencyInjection.Extensions; |
27 | 28 | using Microsoft.Extensions.FileProviders; |
@@ -982,62 +983,72 @@ public async Task Rendering_ComponentWithJsInteropThrows() |
982 | 983 | exception.Message); |
983 | 984 | } |
984 | 985 |
|
985 | | - [Theory] |
| 986 | + [ConditionalTheory] |
| 987 | + [RemoteExecutionSupported] |
986 | 988 | [InlineData(true)] |
987 | 989 | [InlineData(false)] |
988 | | - public async Task UriHelperRedirect_ThrowsInvalidOperationException_WhenResponseHasAlreadyStarted(bool allowException) |
| 990 | + public void UriHelperRedirect_ThrowsInvalidOperationException_WhenResponseHasAlreadyStarted(bool allowException) |
989 | 991 | { |
990 | | - AppContext.SetSwitch("Microsoft.AspNetCore.Components.Endpoints.NavigationManager.DisableThrowNavigationException", isEnabled: !allowException); |
991 | | - // Arrange |
992 | | - var ctx = new DefaultHttpContext(); |
993 | | - ctx.Request.Scheme = "http"; |
994 | | - ctx.Request.Host = new HostString("localhost"); |
995 | | - ctx.Request.PathBase = "/base"; |
996 | | - ctx.Request.Path = "/path"; |
997 | | - ctx.Request.QueryString = new QueryString("?query=value"); |
998 | | - ctx.Response.Body = new MemoryStream(); |
999 | | - var responseMock = new Mock<IHttpResponseFeature>(); |
1000 | | - responseMock.Setup(r => r.HasStarted).Returns(true); |
1001 | | - ctx.Features.Set(responseMock.Object); |
1002 | | - var httpContext = GetHttpContext(ctx); |
1003 | | - string redirectUri = "http://localhost/redirect"; |
| 992 | + var options = new RemoteInvokeOptions(); |
| 993 | + options.RuntimeConfigurationOptions.Add( |
| 994 | + "Microsoft.AspNetCore.Components.Endpoints.NavigationManager.DisableThrowNavigationException", |
| 995 | + (!allowException).ToString().ToLowerInvariant()); |
1004 | 996 |
|
1005 | | - // Act |
1006 | | - if (allowException) |
| 997 | + using var remoteHandle = RemoteExecutor.Invoke(static async (allowExceptionStr) => |
1007 | 998 | { |
1008 | | - var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () => await renderer.PrerenderComponentAsync( |
1009 | | - httpContext, |
1010 | | - typeof(RedirectComponent), |
1011 | | - null, |
1012 | | - ParameterView.FromDictionary(new Dictionary<string, object> |
1013 | | - { |
1014 | | - { "RedirectUri", redirectUri } |
1015 | | - }))); |
1016 | | - |
1017 | | - Assert.Equal("A navigation command was attempted during prerendering after the server already started sending the response. " + |
1018 | | - "Navigation commands can not be issued during server-side prerendering after the response from the server has started. Applications must buffer the" + |
1019 | | - "response and avoid using features like FlushAsync() before all components on the page have been rendered to prevent failed navigation commands.", |
1020 | | - exception.Message); |
1021 | | - } |
1022 | | - else |
1023 | | - { |
1024 | | - await renderer.PrerenderComponentAsync( |
1025 | | - httpContext, |
1026 | | - typeof(RedirectComponent), |
1027 | | - null, |
1028 | | - ParameterView.FromDictionary(new Dictionary<string, object> |
1029 | | - { |
1030 | | - { "RedirectUri", redirectUri } |
1031 | | - })); |
1032 | | - // read the custom element from the response body |
1033 | | - httpContext.Response.Body.Position = 0; |
1034 | | - var reader = new StreamReader(httpContext.Response.Body); |
1035 | | - var output = await reader.ReadToEndAsync(); |
1036 | | - |
1037 | | - // Assert that the output contains expected navigation instructions. |
1038 | | - var pattern = "^<blazor-ssr><template type=\"redirection\".*>.*<\\/template><blazor-ssr-end><\\/blazor-ssr-end><\\/blazor-ssr>$"; |
1039 | | - Assert.Matches(pattern, output); |
1040 | | - } |
| 999 | + var allowException = bool.Parse(allowExceptionStr); |
| 1000 | + var services = CreateDefaultServiceCollection().BuildServiceProvider(); |
| 1001 | + var renderer = new TestEndpointHtmlRenderer(services, NullLoggerFactory.Instance); |
| 1002 | + |
| 1003 | + var ctx = new DefaultHttpContext(); |
| 1004 | + ctx.Request.Scheme = "http"; |
| 1005 | + ctx.Request.Host = new HostString("localhost"); |
| 1006 | + ctx.Request.PathBase = "/base"; |
| 1007 | + ctx.Request.Path = "/path"; |
| 1008 | + ctx.Request.QueryString = new QueryString("?query=value"); |
| 1009 | + ctx.Response.Body = new MemoryStream(); |
| 1010 | + ctx.RequestServices = services; |
| 1011 | + var responseMock = new Mock<IHttpResponseFeature>(); |
| 1012 | + responseMock.Setup(r => r.HasStarted).Returns(true); |
| 1013 | + ctx.Features.Set(responseMock.Object); |
| 1014 | + string redirectUri = "http://localhost/redirect"; |
| 1015 | + |
| 1016 | + if (allowException) |
| 1017 | + { |
| 1018 | + var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () => await renderer.PrerenderComponentAsync( |
| 1019 | + ctx, |
| 1020 | + typeof(RedirectComponent), |
| 1021 | + null, |
| 1022 | + ParameterView.FromDictionary(new Dictionary<string, object> |
| 1023 | + { |
| 1024 | + { "RedirectUri", redirectUri } |
| 1025 | + }))); |
| 1026 | + |
| 1027 | + Assert.Equal("A navigation command was attempted during prerendering after the server already started sending the response. " + |
| 1028 | + "Navigation commands can not be issued during server-side prerendering after the response from the server has started. Applications must buffer the" + |
| 1029 | + "response and avoid using features like FlushAsync() before all components on the page have been rendered to prevent failed navigation commands.", |
| 1030 | + exception.Message); |
| 1031 | + } |
| 1032 | + else |
| 1033 | + { |
| 1034 | + await renderer.PrerenderComponentAsync( |
| 1035 | + ctx, |
| 1036 | + typeof(RedirectComponent), |
| 1037 | + null, |
| 1038 | + ParameterView.FromDictionary(new Dictionary<string, object> |
| 1039 | + { |
| 1040 | + { "RedirectUri", redirectUri } |
| 1041 | + })); |
| 1042 | + // read the custom element from the response body |
| 1043 | + ctx.Response.Body.Position = 0; |
| 1044 | + var reader = new StreamReader(ctx.Response.Body); |
| 1045 | + var output = await reader.ReadToEndAsync(); |
| 1046 | + |
| 1047 | + // Assert that the output contains expected navigation instructions. |
| 1048 | + var pattern = "^<blazor-ssr><template type=\"redirection\".*>.*<\\/template><blazor-ssr-end><\\/blazor-ssr-end><\\/blazor-ssr>$"; |
| 1049 | + Assert.Matches(pattern, output); |
| 1050 | + } |
| 1051 | + }, allowException.ToString(), options); |
1041 | 1052 | } |
1042 | 1053 |
|
1043 | 1054 | [Fact] |
@@ -1343,7 +1354,7 @@ public async Task RenderMode_CanRenderInteractiveComponents() |
1343 | 1354 | lines[0] = AssertAndStripBrowserConfiguration(lines[0]); |
1344 | 1355 | var serverMarkerMatch = Regex.Match(lines[0], PrerenderedComponentPattern); |
1345 | 1356 | var serverNonPrerenderedMarkerMatch = Regex.Match(lines[1], ComponentPattern); |
1346 | | - |
| 1357 | + |
1347 | 1358 | var webAssemblyMarkerMatch = Regex.Match(lines[2], PrerenderedComponentPattern); |
1348 | 1359 | var webAssemblyNonPrerenderedMarkerMatch = Regex.Match(lines[3], ComponentPattern); |
1349 | 1360 |
|
|
0 commit comments