diff --git a/AspNetCore.sln b/AspNetCore.sln index 0682ff1a645f..403bbfaa9977 100644 --- a/AspNetCore.sln +++ b/AspNetCore.sln @@ -1786,6 +1786,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authen EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IdentitySample.ApiEndpoints", "src\Identity\samples\IdentitySample.ApiEndpoints\IdentitySample.ApiEndpoints.csproj", "{37FC77EA-AC44-4D08-B002-8EFF415C424A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Components.WasmMinimal", "src\Components\test\testassets\Components.WasmMinimal\Components.WasmMinimal.csproj", "{87D58D50-20D1-4091-88C5-8D88DCCC2DE3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -10739,6 +10741,22 @@ Global {37FC77EA-AC44-4D08-B002-8EFF415C424A}.Release|x64.Build.0 = Release|Any CPU {37FC77EA-AC44-4D08-B002-8EFF415C424A}.Release|x86.ActiveCfg = Release|Any CPU {37FC77EA-AC44-4D08-B002-8EFF415C424A}.Release|x86.Build.0 = Release|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Debug|arm64.ActiveCfg = Debug|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Debug|arm64.Build.0 = Debug|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Debug|x64.ActiveCfg = Debug|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Debug|x64.Build.0 = Debug|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Debug|x86.ActiveCfg = Debug|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Debug|x86.Build.0 = Debug|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Release|Any CPU.Build.0 = Release|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Release|arm64.ActiveCfg = Release|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Release|arm64.Build.0 = Release|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Release|x64.ActiveCfg = Release|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Release|x64.Build.0 = Release|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Release|x86.ActiveCfg = Release|Any CPU + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -11621,6 +11639,7 @@ Global {56291265-B7BF-4756-92AB-FC30F09381D1} = {822D1519-77F0-484A-B9AB-F694C2CC25F1} {66FA1041-5556-43A0-9CA3-F9937F085F6E} = {56291265-B7BF-4756-92AB-FC30F09381D1} {37FC77EA-AC44-4D08-B002-8EFF415C424A} = {64B2A28F-6D82-4F2B-B0BB-88DE5216DD2C} + {87D58D50-20D1-4091-88C5-8D88DCCC2DE3} = {6126DCE4-9692-4EE2-B240-C65743572995} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F} diff --git a/src/Components/Components.slnf b/src/Components/Components.slnf index e0ae358526d6..005fb7b1e8b9 100644 --- a/src/Components/Components.slnf +++ b/src/Components/Components.slnf @@ -53,6 +53,7 @@ "src\\Components\\test\\E2ETest\\Microsoft.AspNetCore.Components.E2ETests.csproj", "src\\Components\\test\\testassets\\BasicTestApp\\BasicTestApp.csproj", "src\\Components\\test\\testassets\\Components.TestServer\\Components.TestServer.csproj", + "src\\Components\\test\\testassets\\Components.WasmMinimal\\Components.WasmMinimal.csproj", "src\\Components\\test\\testassets\\ComponentsApp.App\\ComponentsApp.App.csproj", "src\\Components\\test\\testassets\\ComponentsApp.Server\\ComponentsApp.Server.csproj", "src\\Components\\test\\testassets\\GlobalizationWasmApp\\GlobalizationWasmApp.csproj", @@ -148,4 +149,4 @@ "src\\WebEncoders\\src\\Microsoft.Extensions.WebEncoders.csproj" ] } -} +} \ No newline at end of file diff --git a/src/Components/Endpoints/src/DependencyInjection/WebAssemblyComponentsEndpointOptions.cs b/src/Components/Endpoints/src/DependencyInjection/WebAssemblyComponentsEndpointOptions.cs new file mode 100644 index 000000000000..69bcc72990f5 --- /dev/null +++ b/src/Components/Endpoints/src/DependencyInjection/WebAssemblyComponentsEndpointOptions.cs @@ -0,0 +1,18 @@ +// 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.Http; + +namespace Microsoft.AspNetCore.Components.Endpoints; + +/// +/// Options to configure interactive WebAssembly components. +/// +public sealed class WebAssemblyComponentsEndpointOptions +{ + /// + /// Gets or sets the that indicates the prefix for Blazor WebAssembly assets. + /// This path must correspond to a referenced Blazor WebAssembly application project. + /// + public PathString PathPrefix { get; set; } +} diff --git a/src/Components/Endpoints/src/PublicAPI.Unshipped.txt b/src/Components/Endpoints/src/PublicAPI.Unshipped.txt index e4528ad1be96..f852122daa03 100644 --- a/src/Components/Endpoints/src/PublicAPI.Unshipped.txt +++ b/src/Components/Endpoints/src/PublicAPI.Unshipped.txt @@ -76,6 +76,10 @@ Microsoft.AspNetCore.Components.Endpoints.RenderModeEndpointProvider.RenderModeE Microsoft.AspNetCore.Components.Endpoints.RootComponentMetadata Microsoft.AspNetCore.Components.Endpoints.RootComponentMetadata.RootComponentMetadata(System.Type! rootComponentType) -> void Microsoft.AspNetCore.Components.Endpoints.RootComponentMetadata.Type.get -> System.Type! +Microsoft.AspNetCore.Components.Endpoints.WebAssemblyComponentsEndpointOptions +Microsoft.AspNetCore.Components.Endpoints.WebAssemblyComponentsEndpointOptions.PathPrefix.get -> Microsoft.AspNetCore.Http.PathString +Microsoft.AspNetCore.Components.Endpoints.WebAssemblyComponentsEndpointOptions.PathPrefix.set -> void +Microsoft.AspNetCore.Components.Endpoints.WebAssemblyComponentsEndpointOptions.WebAssemblyComponentsEndpointOptions() -> void Microsoft.AspNetCore.Components.Infrastructure.RazorComponentApplicationAttribute Microsoft.AspNetCore.Components.Infrastructure.RazorComponentApplicationAttribute.RazorComponentApplicationAttribute() -> void Microsoft.AspNetCore.Components.PersistedStateSerializationMode @@ -91,4 +95,4 @@ static Microsoft.AspNetCore.Builder.RazorComponentsEndpointRouteBuilderExtension static Microsoft.AspNetCore.Components.Discovery.ComponentApplicationBuilder.GetBuilder() -> Microsoft.AspNetCore.Components.Discovery.ComponentApplicationBuilder? static Microsoft.Extensions.DependencyInjection.RazorComponentsServiceCollectionExtensions.AddRazorComponents(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.AspNetCore.Components.Endpoints.IRazorComponentsBuilder! static readonly Microsoft.AspNetCore.Components.Endpoints.RazorComponentResultExecutor.DefaultContentType -> string! -virtual Microsoft.AspNetCore.Components.Endpoints.RazorComponentResultExecutor.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext, Microsoft.AspNetCore.Components.Endpoints.RazorComponentResult! result) -> System.Threading.Tasks.Task! \ No newline at end of file +virtual Microsoft.AspNetCore.Components.Endpoints.RazorComponentResultExecutor.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext, Microsoft.AspNetCore.Components.Endpoints.RazorComponentResult! result) -> System.Threading.Tasks.Task! diff --git a/src/Components/WebAssembly/Server/src/Microsoft.AspNetCore.Components.WebAssembly.Server.csproj b/src/Components/WebAssembly/Server/src/Microsoft.AspNetCore.Components.WebAssembly.Server.csproj index ba032dcf8f79..2bd9c32a565a 100644 --- a/src/Components/WebAssembly/Server/src/Microsoft.AspNetCore.Components.WebAssembly.Server.csproj +++ b/src/Components/WebAssembly/Server/src/Microsoft.AspNetCore.Components.WebAssembly.Server.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Components/WebAssembly/Server/src/PublicAPI.Unshipped.txt b/src/Components/WebAssembly/Server/src/PublicAPI.Unshipped.txt index bbfd1c31db86..814dd116adf0 100644 --- a/src/Components/WebAssembly/Server/src/PublicAPI.Unshipped.txt +++ b/src/Components/WebAssembly/Server/src/PublicAPI.Unshipped.txt @@ -1,2 +1,4 @@ #nullable enable Microsoft.AspNetCore.Components.WebAssembly.Server.TargetPickerUi.DisplayFirefox(Microsoft.AspNetCore.Http.HttpContext! context) -> System.Threading.Tasks.Task! +Microsoft.Extensions.DependencyInjection.RazorComponentsBuilderExtensions +static Microsoft.Extensions.DependencyInjection.RazorComponentsBuilderExtensions.AddWebAssemblyComponents(this Microsoft.AspNetCore.Components.Endpoints.IRazorComponentsBuilder! builder, System.Action? configure = null) -> Microsoft.AspNetCore.Components.Endpoints.IRazorComponentsBuilder! diff --git a/src/Components/WebAssembly/Server/src/RazorComponentsBuilderExtensions.cs b/src/Components/WebAssembly/Server/src/RazorComponentsBuilderExtensions.cs new file mode 100644 index 000000000000..9d1a7004c435 --- /dev/null +++ b/src/Components/WebAssembly/Server/src/RazorComponentsBuilderExtensions.cs @@ -0,0 +1,112 @@ +// 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.Builder; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Endpoints; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// Extension methods to configure an for WebAssembly components. +/// +public static class RazorComponentsBuilderExtensions +{ + /// + /// Adds services to support rendering interactive WebAssembly components. + /// + /// The . + /// A callback to configure . + /// An that can be used to further customize the configuration. + public static IRazorComponentsBuilder AddWebAssemblyComponents(this IRazorComponentsBuilder builder, Action? configure = null) + { + ArgumentNullException.ThrowIfNull(builder, nameof(builder)); + + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); + + if (configure is not null) + { + builder.Services.Configure(configure); + } + + return builder; + } + + private class WebAssemblyEndpointProvider : RenderModeEndpointProvider + { + private readonly IServiceProvider _services; + private readonly WebAssemblyComponentsEndpointOptions _options; + + public WebAssemblyEndpointProvider(IServiceProvider services, IOptions options) + { + _services = services; + _options = options.Value; + } + + public override IEnumerable GetEndpointBuilders(IComponentRenderMode renderMode, IApplicationBuilder applicationBuilder) + { + var endpointRouteBuilder = new EndpointRouteBuilder(_services, applicationBuilder); + var pathPrefix = _options.PathPrefix; + + applicationBuilder.UseBlazorFrameworkFiles(pathPrefix); + var app = applicationBuilder.Build(); + + endpointRouteBuilder.Map($"{pathPrefix}/_framework/{{*path}}", context => + { + // Set endpoint to null so the static files middleware will handle the request. + context.SetEndpoint(null); + + return app(context); + }); + + return endpointRouteBuilder.GetEndpoints(); + } + + public override bool Supports(IComponentRenderMode renderMode) + => renderMode is WebAssemblyRenderMode or AutoRenderMode; + + private class EndpointRouteBuilder : IEndpointRouteBuilder + { + private readonly IApplicationBuilder _applicationBuilder; + + public EndpointRouteBuilder(IServiceProvider serviceProvider, IApplicationBuilder applicationBuilder) + { + ServiceProvider = serviceProvider; + _applicationBuilder = applicationBuilder; + } + + public IServiceProvider ServiceProvider { get; } + + public ICollection DataSources { get; } = new List() { }; + + public IApplicationBuilder CreateApplicationBuilder() + { + return _applicationBuilder.New(); + } + + internal IEnumerable GetEndpoints() + { + foreach (var ds in DataSources) + { + foreach (var endpoint in ds.Endpoints) + { + var routeEndpoint = (RouteEndpoint)endpoint; + var builder = new RouteEndpointBuilder(endpoint.RequestDelegate, routeEndpoint.RoutePattern, routeEndpoint.Order); + for (var i = 0; i < routeEndpoint.Metadata.Count; i++) + { + var metadata = routeEndpoint.Metadata[i]; + builder.Metadata.Add(metadata); + } + + yield return builder; + } + } + } + } + } +} diff --git a/src/Components/test/E2ETest/ServerRenderingTests/InteractivityTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/InteractivityTest.cs new file mode 100644 index 000000000000..b1735e538f2a --- /dev/null +++ b/src/Components/test/E2ETest/ServerRenderingTests/InteractivityTest.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Components.TestServer.RazorComponents; +using Microsoft.AspNetCore.Components.E2ETest.Infrastructure; +using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; +using Microsoft.AspNetCore.E2ETesting; +using OpenQA.Selenium; +using TestServer; +using Xunit.Abstractions; + +namespace Microsoft.AspNetCore.Components.E2ETests.ServerRenderingTests; + +public class InteractivityTest : ServerTestBase>> +{ + public InteractivityTest( + BrowserFixture browserFixture, + BasicTestAppServerSiteFixture> serverFixture, + ITestOutputHelper output) + : base(browserFixture, serverFixture, output) + { + } + + public override Task InitializeAsync() + => InitializeAsync(BrowserFixture.StreamingContext); + + [Fact] + public void CanRenderInteractiveServerComponent() + { + // '2' configures the increment amount. + Navigate($"{ServerPathBase}/interactive?server=2"); + + Browser.Equal("0", () => Browser.FindElement(By.Id("count-server")).Text); + Browser.Equal("True", () => Browser.FindElement(By.Id("is-interactive-server")).Text); + + Browser.Click(By.Id("increment-server")); + + Browser.Equal("2", () => Browser.FindElement(By.Id("count-server")).Text); + } + + [Fact] + public void CanRenderInteractiveServerComponentFromRazorClassLibrary() + { + // '3' configures the increment amount. + Navigate($"{ServerPathBase}/interactive?server-shared=3"); + + Browser.Equal("0", () => Browser.FindElement(By.Id("count-server-shared")).Text); + Browser.Equal("True", () => Browser.FindElement(By.Id("is-interactive-server-shared")).Text); + + Browser.Click(By.Id("increment-server-shared")); + + Browser.Equal("3", () => Browser.FindElement(By.Id("count-server-shared")).Text); + } + + [Fact] + public void CanRenderInteractiveWebAssemblyComponentFromRazorClassLibrary() + { + // '4' configures the increment amount. + Navigate($"{ServerPathBase}/interactive?wasm-shared=4"); + + Browser.Equal("0", () => Browser.FindElement(By.Id("count-wasm-shared")).Text); + Browser.Equal("True", () => Browser.FindElement(By.Id("is-interactive-wasm-shared")).Text); + + Browser.Click(By.Id("increment-wasm-shared")); + + Browser.Equal("4", () => Browser.FindElement(By.Id("count-wasm-shared")).Text); + } + + [Fact] + public void CanRenderInteractiveServerAndWebAssemblyComponentsAtTheSameTime() + { + // '3' and '5' configure the increment amounts. + Navigate($"{ServerPathBase}/interactive?server-shared=3&wasm-shared=5"); + + Browser.Equal("0", () => Browser.FindElement(By.Id("count-server-shared")).Text); + Browser.Equal("0", () => Browser.FindElement(By.Id("count-wasm-shared")).Text); + Browser.Equal("True", () => Browser.FindElement(By.Id("is-interactive-server-shared")).Text); + Browser.Equal("True", () => Browser.FindElement(By.Id("is-interactive-wasm-shared")).Text); + + Browser.Click(By.Id("increment-server-shared")); + Browser.Click(By.Id("increment-wasm-shared")); + + Browser.Equal("3", () => Browser.FindElement(By.Id("count-server-shared")).Text); + Browser.Equal("5", () => Browser.FindElement(By.Id("count-wasm-shared")).Text); + } +} diff --git a/src/Components/test/testassets/Components.TestServer/Components.TestServer.csproj b/src/Components/test/testassets/Components.TestServer/Components.TestServer.csproj index c0d29d8eae4d..fd1ad17595e6 100644 --- a/src/Components/test/testassets/Components.TestServer/Components.TestServer.csproj +++ b/src/Components/test/testassets/Components.TestServer/Components.TestServer.csproj @@ -27,6 +27,7 @@ + diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs b/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs index 87aa55f5d1f3..0da1eb13c0cd 100644 --- a/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs @@ -22,7 +22,12 @@ 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) { - services.AddRazorComponents(); + services.AddRazorComponents() + .AddServerComponents() + .AddWebAssemblyComponents(options => + { + options.PathPrefix = "/WasmMinimal"; + }); services.AddHttpContextAccessor(); services.AddSingleton(); } @@ -41,10 +46,13 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.Map("/subdir", app => { + app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { - endpoints.MapRazorComponents(); + endpoints.MapRazorComponents() + .AddServerRenderMode() + .AddWebAssemblyRenderMode(); StreamingRendering.MapEndpoints(endpoints); StreamingRenderingForm.MapEndpoints(endpoints); diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor index 142eca4b7fea..bbef6b531009 100644 --- a/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor +++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor @@ -20,6 +20,15 @@ - + + diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Components/ServerInteractiveCounter.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Components/ServerInteractiveCounter.razor new file mode 100644 index 000000000000..7ca2b4b0468c --- /dev/null +++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Components/ServerInteractiveCounter.razor @@ -0,0 +1,9 @@ +@attribute [RenderModeServer] + +Server counter + + +@code { + [Parameter] + public int IncrementAmount { get; set; } = 1; +} diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/InteractiveComponents.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/InteractiveComponents.razor new file mode 100644 index 000000000000..e8229f750877 --- /dev/null +++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/InteractiveComponents.razor @@ -0,0 +1,32 @@ +@page "/interactive" + +

Interactive components

+ +@if (ServerIncrementAmount.HasValue) +{ + +
+} + +@if (ServerSharedIncrementAmount.HasValue) +{ + +
+} + +@if (SharedWebAssemblyIncrementAmount.HasValue) +{ + +
+} + +@code { + [Parameter, SupplyParameterFromQuery(Name = "server")] + public int? ServerIncrementAmount { get; set; } + + [Parameter, SupplyParameterFromQuery(Name = "server-shared")] + public int? ServerSharedIncrementAmount { get; set; } + + [Parameter, SupplyParameterFromQuery(Name = "wasm-shared")] + public int? SharedWebAssemblyIncrementAmount { get; set; } +} diff --git a/src/Components/test/testassets/Components.WasmMinimal/Components.WasmMinimal.csproj b/src/Components/test/testassets/Components.WasmMinimal/Components.WasmMinimal.csproj new file mode 100644 index 000000000000..a02754633bb7 --- /dev/null +++ b/src/Components/test/testassets/Components.WasmMinimal/Components.WasmMinimal.csproj @@ -0,0 +1,18 @@ + + + + $(DefaultNetCoreTargetFramework) + enable + enable + WasmMinimal + + + + + + + + + + + diff --git a/src/Components/test/testassets/Components.WasmMinimal/Program.cs b/src/Components/test/testassets/Components.WasmMinimal/Program.cs new file mode 100644 index 000000000000..945c94a24a65 --- /dev/null +++ b/src/Components/test/testassets/Components.WasmMinimal/Program.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; + +Assembly.Load(nameof(TestContentPackage)); + +var builder = WebAssemblyHostBuilder.CreateDefault(args); +await builder.Build().RunAsync(); diff --git a/src/Components/test/testassets/TestContentPackage/Counter.razor b/src/Components/test/testassets/TestContentPackage/Counter.razor new file mode 100644 index 000000000000..596f70bc40c5 --- /dev/null +++ b/src/Components/test/testassets/TestContentPackage/Counter.razor @@ -0,0 +1,30 @@ +

Increment amount: @IncrementAmount

+

Interactive: @_isInteractive

+

Current count: @_currentCount

+ + + +@code { + private int _currentCount = 0; + private bool _isInteractive = false; + + [Parameter, EditorRequired] + public int IncrementAmount { get; set; } + + [Parameter, EditorRequired] + public string IdSuffix { get; set; } + + private void IncrementCount() + { + _currentCount += IncrementAmount; + } + + protected override void OnAfterRender(bool firstRender) + { + if (firstRender) + { + _isInteractive = true; + StateHasChanged(); + } + } +} diff --git a/src/Components/test/testassets/TestContentPackage/ServerInteractiveCounter.razor b/src/Components/test/testassets/TestContentPackage/ServerInteractiveCounter.razor new file mode 100644 index 000000000000..1513ea58149e --- /dev/null +++ b/src/Components/test/testassets/TestContentPackage/ServerInteractiveCounter.razor @@ -0,0 +1,9 @@ +@attribute [RenderModeServer] + +Server counter from RCL + + +@code { + [Parameter] + public int IncrementAmount { get; set; } = 1; +} diff --git a/src/Components/test/testassets/TestContentPackage/WebAssemblyInteractiveCounter.razor b/src/Components/test/testassets/TestContentPackage/WebAssemblyInteractiveCounter.razor new file mode 100644 index 000000000000..67666e87093f --- /dev/null +++ b/src/Components/test/testassets/TestContentPackage/WebAssemblyInteractiveCounter.razor @@ -0,0 +1,9 @@ +@attribute [RenderModeWebAssembly] + +WebAssembly counter from RCL + + +@code { + [Parameter] + public int IncrementAmount { get; set; } = 1; +} diff --git a/src/Framework/Framework.slnf b/src/Framework/Framework.slnf index 90f44250d2da..e16be1588531 100644 --- a/src/Framework/Framework.slnf +++ b/src/Framework/Framework.slnf @@ -10,6 +10,7 @@ "src\\Components\\Forms\\src\\Microsoft.AspNetCore.Components.Forms.csproj", "src\\Components\\Server\\src\\Microsoft.AspNetCore.Components.Server.csproj", "src\\Components\\Web\\src\\Microsoft.AspNetCore.Components.Web.csproj", + "src\\Components\\WebAssembly\\Server\\src\\Microsoft.AspNetCore.Components.WebAssembly.Server.csproj", "src\\Configuration.KeyPerFile\\src\\Microsoft.Extensions.Configuration.KeyPerFile.csproj", "src\\DataProtection\\Abstractions\\src\\Microsoft.AspNetCore.DataProtection.Abstractions.csproj", "src\\DataProtection\\Cryptography.Internal\\src\\Microsoft.AspNetCore.Cryptography.Internal.csproj", @@ -110,4 +111,4 @@ "src\\WebEncoders\\src\\Microsoft.Extensions.WebEncoders.csproj" ] } -} \ No newline at end of file +}