diff --git a/.editorconfig b/.editorconfig index 35147d7db8..00aaa787e7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,14 @@ ; EditorConfig to support per-solution formatting. ; Use the EditorConfig VS add-in to make this work. ; http://editorconfig.org/ +; +; Here are some resources for what's supported for .NET/C# +; https://kent-boogaart.com/blog/editorconfig-reference-for-c-developers +; https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference?view=vs-2017 +; +; Be **careful** editing this because some of the rules don't support adding a severity level +; For instance if you change to `dotnet_sort_system_directives_first = true:warning` (adding `:warning`) +; then the rule will be silently ignored. ; This is the default for the codeline. root = true @@ -13,7 +21,7 @@ insert_final_newline = true [*.cs] indent_size = 4 -dotnet_sort_system_directives_first = true:warning +dotnet_sort_system_directives_first = true [*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}] indent_size = 2 diff --git a/src/Components/Analyzers/src/ComponentsApi.cs b/src/Components/Analyzers/src/ComponentsApi.cs new file mode 100644 index 0000000000..fdb83c6f05 --- /dev/null +++ b/src/Components/Analyzers/src/ComponentsApi.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Components.Shared +{ + // Constants for type and method names used in code-generation + // Keep these in sync with the actual definitions + internal static class ComponentsApi + { + public static readonly string AssemblyName = "Microsoft.AspNetCore.Components"; + + public static class ParameterAttribute + { + public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.ParameterAttribute"; + public static readonly string MetadataName = FullTypeName; + } + } +} diff --git a/src/Components/Analyzers/src/Microsoft.AspNetCore.Components.Analyzers.csproj b/src/Components/Analyzers/src/Microsoft.AspNetCore.Components.Analyzers.csproj index bf85dcfae2..3ad086e33b 100644 --- a/src/Components/Analyzers/src/Microsoft.AspNetCore.Components.Analyzers.csproj +++ b/src/Components/Analyzers/src/Microsoft.AspNetCore.Components.Analyzers.csproj @@ -20,7 +20,6 @@ - True True diff --git a/src/Components/Analyzers/test/ComponentParametersShouldNotBePublicTest.cs b/src/Components/Analyzers/test/ComponentParametersShouldNotBePublicTest.cs index e79bcf12aa..1a4f93a5a6 100644 --- a/src/Components/Analyzers/test/ComponentParametersShouldNotBePublicTest.cs +++ b/src/Components/Analyzers/test/ComponentParametersShouldNotBePublicTest.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Components.Analyzers.Test { public class ComponentParametersShouldNotBePublic : CodeFixVerifier { - static string BlazorParameterSource = $@" + static string ParameterSource = $@" namespace {typeof(ParameterAttribute).Namespace} {{ public class {typeof(ParameterAttribute).Name} : System.Attribute @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Components.Analyzers.Test { public string MyProperty { get; set; } } - }" + BlazorParameterSource; + }" + ParameterSource; VerifyCSharpDiagnostic(test); } @@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Components.Analyzers.Test [Parameter] protected string MyPropertyProtected { get; set; } [Parameter] internal string MyPropertyInternal { get; set; } } - }" + BlazorParameterSource; + }" + ParameterSource; VerifyCSharpDiagnostic(test); } @@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Components.Analyzers.Test [Parameter] public string BadProperty1 { get; set; } [Parameter] public object BadProperty2 { get; set; } } - }" + BlazorParameterSource; + }" + ParameterSource; VerifyCSharpDiagnostic(test, new DiagnosticResult @@ -103,7 +103,7 @@ namespace Microsoft.AspNetCore.Components.Analyzers.Test [Parameter] string BadProperty1 { get; set; } [Parameter] object BadProperty2 { get; set; } } - }" + BlazorParameterSource); + }" + ParameterSource); } [Fact] @@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Components.Analyzers.Test [Parameter] public object MyProperty2 { get; protected set; } [Parameter] public object MyProperty2 { get; internal set; } } - }" + BlazorParameterSource; + }" + ParameterSource; VerifyCSharpDiagnostic(test); } diff --git a/src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.netstandard2.0.cs b/src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.netstandard2.0.cs index be4ef7e47b..878e2a3380 100644 --- a/src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.netstandard2.0.cs +++ b/src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.netstandard2.0.cs @@ -78,3 +78,15 @@ namespace Microsoft.AspNetCore.Blazor.Services public static void NotifyLocationChanged(string newAbsoluteUri) { } } } +namespace Microsoft.AspNetCore.Components.Builder +{ + public static partial class ComponentsApplicationBuilderExtensions + { + public static void AddComponent(this Microsoft.AspNetCore.Components.Builder.IComponentsApplicationBuilder app, string domElementSelector) where TComponent : Microsoft.AspNetCore.Components.IComponent { } + } + public partial interface IComponentsApplicationBuilder + { + System.IServiceProvider Services { get; } + void AddComponent(System.Type componentType, string domElementSelector); + } +} diff --git a/src/Components/Components/src/Builder/ComponentsApplicationBuilderExtensions.cs b/src/Components/Blazor/Blazor/src/Builder/ComponentsApplicationBuilderExtensions.cs similarity index 100% rename from src/Components/Components/src/Builder/ComponentsApplicationBuilderExtensions.cs rename to src/Components/Blazor/Blazor/src/Builder/ComponentsApplicationBuilderExtensions.cs diff --git a/src/Components/Components/src/Builder/IComponentsApplicationBuilder.cs b/src/Components/Blazor/Blazor/src/Builder/IComponentsApplicationBuilder.cs similarity index 100% rename from src/Components/Components/src/Builder/IComponentsApplicationBuilder.cs rename to src/Components/Blazor/Blazor/src/Builder/IComponentsApplicationBuilder.cs diff --git a/src/Components/Shared/src/ConventionBasedStartup.cs b/src/Components/Blazor/Blazor/src/Hosting/ConventionBasedStartup.cs similarity index 98% rename from src/Components/Shared/src/ConventionBasedStartup.cs rename to src/Components/Blazor/Blazor/src/Hosting/ConventionBasedStartup.cs index 4afc211d4b..53eecbf6e0 100644 --- a/src/Components/Shared/src/ConventionBasedStartup.cs +++ b/src/Components/Blazor/Blazor/src/Hosting/ConventionBasedStartup.cs @@ -9,7 +9,7 @@ using System.Runtime.ExceptionServices; using Microsoft.AspNetCore.Components.Builder; using Microsoft.Extensions.DependencyInjection; -namespace Microsoft.AspNetCore.Components.Hosting +namespace Microsoft.AspNetCore.Blazor.Hosting { // Keeping this simple for now to focus on predictable and reasonable behaviors. // Startup in WebHost supports lots of things we don't yet support, and some we diff --git a/src/Components/Shared/src/IBlazorStartup.cs b/src/Components/Blazor/Blazor/src/Hosting/IBlazorStartup.cs similarity index 90% rename from src/Components/Shared/src/IBlazorStartup.cs rename to src/Components/Blazor/Blazor/src/Hosting/IBlazorStartup.cs index 3f6d71d16e..e87138387f 100644 --- a/src/Components/Shared/src/IBlazorStartup.cs +++ b/src/Components/Blazor/Blazor/src/Hosting/IBlazorStartup.cs @@ -5,7 +5,7 @@ using System; using Microsoft.AspNetCore.Components.Builder; using Microsoft.Extensions.DependencyInjection; -namespace Microsoft.AspNetCore.Components.Hosting +namespace Microsoft.AspNetCore.Blazor.Hosting { internal interface IBlazorStartup { diff --git a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHost.cs b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHost.cs index 19e0e67f87..b68aa3c36e 100644 --- a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHost.cs +++ b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHost.cs @@ -8,7 +8,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Blazor.Http; using Microsoft.AspNetCore.Blazor.Rendering; -using Microsoft.AspNetCore.Components.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.JSInterop; diff --git a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilderExtensions.cs b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilderExtensions.cs index fd0d795944..9b03c09766 100644 --- a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilderExtensions.cs +++ b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilderExtensions.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Components.Hosting; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Blazor.Hosting diff --git a/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj b/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj index 97fba4e00a..49318e9adf 100644 --- a/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj +++ b/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj @@ -11,9 +11,4 @@ - - - - - diff --git a/src/Components/Blazor/Server/ref/Microsoft.AspNetCore.Blazor.Server.csproj b/src/Components/Blazor/Server/ref/Microsoft.AspNetCore.Blazor.Server.csproj index 9bd2886c66..b72d6c201c 100644 --- a/src/Components/Blazor/Server/ref/Microsoft.AspNetCore.Blazor.Server.csproj +++ b/src/Components/Blazor/Server/ref/Microsoft.AspNetCore.Blazor.Server.csproj @@ -6,7 +6,10 @@ + + + diff --git a/src/Components/Blazor/Server/ref/Microsoft.AspNetCore.Blazor.Server.netcoreapp3.0.cs b/src/Components/Blazor/Server/ref/Microsoft.AspNetCore.Blazor.Server.netcoreapp3.0.cs index 124b22205d..deb4cfda2d 100644 --- a/src/Components/Blazor/Server/ref/Microsoft.AspNetCore.Blazor.Server.netcoreapp3.0.cs +++ b/src/Components/Blazor/Server/ref/Microsoft.AspNetCore.Blazor.Server.netcoreapp3.0.cs @@ -3,8 +3,18 @@ namespace Microsoft.AspNetCore.Builder { + public static partial class BlazorApplicationBuilderExtensions + { + public static Microsoft.AspNetCore.Builder.IApplicationBuilder UseBlazor(this Microsoft.AspNetCore.Builder.IApplicationBuilder app, Microsoft.AspNetCore.Builder.BlazorOptions options) { throw null; } + public static Microsoft.AspNetCore.Builder.IApplicationBuilder UseBlazor(this Microsoft.AspNetCore.Builder.IApplicationBuilder app) { throw null; } + } public static partial class BlazorMonoDebugProxyAppBuilderExtensions { public static void UseBlazorDebugging(this Microsoft.AspNetCore.Builder.IApplicationBuilder app) { } } + public partial class BlazorOptions + { + public BlazorOptions() { } + public string ClientAssemblyPath { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + } } diff --git a/src/Components/Server/src/AutoRebuild/AutoRebuildExtensions.cs b/src/Components/Blazor/Server/src/AutoRebuild/AutoRebuildExtensions.cs similarity index 98% rename from src/Components/Server/src/AutoRebuild/AutoRebuildExtensions.cs rename to src/Components/Blazor/Server/src/AutoRebuild/AutoRebuildExtensions.cs index d230aa03c3..6a43600bb9 100644 --- a/src/Components/Server/src/AutoRebuild/AutoRebuildExtensions.cs +++ b/src/Components/Blazor/Server/src/AutoRebuild/AutoRebuildExtensions.cs @@ -1,15 +1,15 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Components.Server; -using Microsoft.AspNetCore.Components.Server.AutoRebuild; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Blazor.Server; +using Microsoft.AspNetCore.Blazor.Server.AutoRebuild; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Builder { diff --git a/src/Components/Server/src/AutoRebuild/IRebuildService.cs b/src/Components/Blazor/Server/src/AutoRebuild/IRebuildService.cs similarity index 80% rename from src/Components/Server/src/AutoRebuild/IRebuildService.cs rename to src/Components/Blazor/Server/src/AutoRebuild/IRebuildService.cs index 5e31af2d38..6e9616e4bf 100644 --- a/src/Components/Server/src/AutoRebuild/IRebuildService.cs +++ b/src/Components/Blazor/Server/src/AutoRebuild/IRebuildService.cs @@ -1,10 +1,10 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Threading.Tasks; -namespace Microsoft.AspNetCore.Components.Server.AutoRebuild +namespace Microsoft.AspNetCore.Blazor.Server.AutoRebuild { /// /// Represents a mechanism for rebuilding a .NET project. For example, it diff --git a/src/Components/Server/src/AutoRebuild/ProcessUtils.cs b/src/Components/Blazor/Server/src/AutoRebuild/ProcessUtils.cs similarity index 93% rename from src/Components/Server/src/AutoRebuild/ProcessUtils.cs rename to src/Components/Blazor/Server/src/AutoRebuild/ProcessUtils.cs index 223208476d..af63853ed9 100644 --- a/src/Components/Server/src/AutoRebuild/ProcessUtils.cs +++ b/src/Components/Blazor/Server/src/AutoRebuild/ProcessUtils.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -6,7 +6,7 @@ using System.ComponentModel; using System.Diagnostics; using System.Runtime.InteropServices; -namespace Microsoft.AspNetCore.Components.Server.AutoRebuild +namespace Microsoft.AspNetCore.Blazor.Server.AutoRebuild { internal static class ProcessUtils { diff --git a/src/Components/Server/src/AutoRebuild/StreamProtocolExtensions.cs b/src/Components/Blazor/Server/src/AutoRebuild/StreamProtocolExtensions.cs similarity index 91% rename from src/Components/Server/src/AutoRebuild/StreamProtocolExtensions.cs rename to src/Components/Blazor/Server/src/AutoRebuild/StreamProtocolExtensions.cs index cd8e375f14..394b26073d 100644 --- a/src/Components/Server/src/AutoRebuild/StreamProtocolExtensions.cs +++ b/src/Components/Blazor/Server/src/AutoRebuild/StreamProtocolExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -6,7 +6,7 @@ using System.IO; using System.Text; using System.Threading.Tasks; -namespace Microsoft.AspNetCore.Components.Server.AutoRebuild +namespace Microsoft.AspNetCore.Blazor.Server.AutoRebuild { internal static class StreamProtocolExtensions { diff --git a/src/Components/Server/src/AutoRebuild/VSForWindowsRebuildService.cs b/src/Components/Blazor/Server/src/AutoRebuild/VSForWindowsRebuildService.cs similarity index 97% rename from src/Components/Server/src/AutoRebuild/VSForWindowsRebuildService.cs rename to src/Components/Blazor/Server/src/AutoRebuild/VSForWindowsRebuildService.cs index d5217ae6ec..92d99d57dd 100644 --- a/src/Components/Server/src/AutoRebuild/VSForWindowsRebuildService.cs +++ b/src/Components/Blazor/Server/src/AutoRebuild/VSForWindowsRebuildService.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -7,7 +7,7 @@ using System.IO.Pipes; using System.Runtime.InteropServices; using System.Threading.Tasks; -namespace Microsoft.AspNetCore.Components.Server.AutoRebuild +namespace Microsoft.AspNetCore.Blazor.Server.AutoRebuild { /// /// Finds the VS process that launched this app process (if any), and uses diff --git a/src/Components/Server/src/BlazorConfig.cs b/src/Components/Blazor/Server/src/BlazorConfig.cs similarity index 97% rename from src/Components/Server/src/BlazorConfig.cs rename to src/Components/Blazor/Server/src/BlazorConfig.cs index da74faf213..79bf6ac6bb 100644 --- a/src/Components/Server/src/BlazorConfig.cs +++ b/src/Components/Blazor/Server/src/BlazorConfig.cs @@ -5,7 +5,7 @@ using System; using System.IO; using System.Linq; -namespace Microsoft.AspNetCore.Components.Server +namespace Microsoft.AspNetCore.Blazor.Server { internal class BlazorConfig { diff --git a/src/Components/Server/src/Builder/BlazorApplicationBuilderExtensions.cs b/src/Components/Blazor/Server/src/Builder/BlazorApplicationBuilderExtensions.cs similarity index 85% rename from src/Components/Server/src/Builder/BlazorApplicationBuilderExtensions.cs rename to src/Components/Blazor/Server/src/Builder/BlazorApplicationBuilderExtensions.cs index 7c7048ed2c..e8b7444cdb 100644 --- a/src/Components/Server/src/Builder/BlazorApplicationBuilderExtensions.cs +++ b/src/Components/Blazor/Server/src/Builder/BlazorApplicationBuilderExtensions.cs @@ -1,15 +1,14 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Components.Server; -using Microsoft.AspNetCore.StaticFiles; -using Microsoft.Extensions.FileProviders; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Net.Http.Headers; -using System.Net.Mime; using System; using System.IO; +using System.Net.Mime; +using Microsoft.AspNetCore.Blazor.Server; +using Microsoft.Extensions.FileProviders; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Hosting; namespace Microsoft.AspNetCore.Builder @@ -70,7 +69,7 @@ namespace Microsoft.AspNetCore.Builder { FileProvider = new PhysicalFileProvider(config.DistPath), ContentTypeProvider = CreateContentTypeProvider(config.EnableDebugging), - OnPrepareResponse = SetCacheHeaders + OnPrepareResponse = CacheHeaderSettings.SetCacheHeaders, }); // * Before publishing, we serve the wwwroot files directly from source @@ -84,7 +83,7 @@ namespace Microsoft.AspNetCore.Builder app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(config.WebRootPath), - OnPrepareResponse = SetCacheHeaders + OnPrepareResponse = CacheHeaderSettings.SetCacheHeaders, }); } @@ -97,7 +96,7 @@ namespace Microsoft.AspNetCore.Builder ? null : new StaticFileOptions { FileProvider = new PhysicalFileProvider(Path.GetDirectoryName(indexHtmlPath)), - OnPrepareResponse = SetCacheHeaders + OnPrepareResponse = CacheHeaderSettings.SetCacheHeaders, }; childAppBuilder.UseSpa(spa => @@ -136,24 +135,6 @@ namespace Microsoft.AspNetCore.Builder return null; } - internal static void SetCacheHeaders(StaticFileResponseContext ctx) - { - // By setting "Cache-Control: no-cache", we're allowing the browser to store - // a cached copy of the response, but telling it that it must check with the - // server for modifications (based on Etag) before using that cached copy. - // Longer term, we should generate URLs based on content hashes (at least - // for published apps) so that the browser doesn't need to make any requests - // for unchanged files. - var headers = ctx.Context.Response.GetTypedHeaders(); - if (headers.CacheControl == null) - { - headers.CacheControl = new CacheControlHeaderValue - { - NoCache = true - }; - } - } - private static bool IsNotFrameworkDir(HttpContext context) => !context.Request.Path.StartsWithSegments("/_framework"); diff --git a/src/Components/Server/src/BlazorOptions.cs b/src/Components/Blazor/Server/src/Builder/BlazorOptions.cs similarity index 100% rename from src/Components/Server/src/BlazorOptions.cs rename to src/Components/Blazor/Server/src/Builder/BlazorOptions.cs diff --git a/src/Components/Blazor/Server/src/Microsoft.AspNetCore.Blazor.Server.csproj b/src/Components/Blazor/Server/src/Microsoft.AspNetCore.Blazor.Server.csproj index 6cc0b40a19..7770f6bdd2 100644 --- a/src/Components/Blazor/Server/src/Microsoft.AspNetCore.Blazor.Server.csproj +++ b/src/Components/Blazor/Server/src/Microsoft.AspNetCore.Blazor.Server.csproj @@ -6,10 +6,16 @@ true + + + + + + - + diff --git a/src/Components/Blazor/testassets/MonoSanity/MonoSanity.csproj b/src/Components/Blazor/testassets/MonoSanity/MonoSanity.csproj index 985bc678b9..3afb1cf708 100644 --- a/src/Components/Blazor/testassets/MonoSanity/MonoSanity.csproj +++ b/src/Components/Blazor/testassets/MonoSanity/MonoSanity.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Components/Browser/src/RendererRegistry.cs b/src/Components/Browser/src/RendererRegistry.cs index 7f2d4c5804..69298c3fc9 100644 --- a/src/Components/Browser/src/RendererRegistry.cs +++ b/src/Components/Browser/src/RendererRegistry.cs @@ -23,13 +23,13 @@ namespace Microsoft.AspNetCore.Components.Browser // By default the registry will be set to a default value. This means that // things will 'just work when running in the browser. // - // Running in Server-Side Blazor - any call into the Circuit will set this value via + // Running in Server-Side Components - any call into the Circuit will set this value via // the async local. This will ensure that the incoming call can resolve the correct // renderer associated with the user context. static RendererRegistry() { _current = new AsyncLocal(); - _globalRegistry = new RendererRegistry(); + _globalRegistry = new RendererRegistry(); } /// diff --git a/src/Components/Components.sln b/src/Components/Components.sln index 17e920c954..e798f22274 100644 --- a/src/Components/Components.sln +++ b/src/Components/Components.sln @@ -207,7 +207,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Ne EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPatch", "..\Features\JsonPatch\src\Microsoft.AspNetCore.JsonPatch.csproj", "{DC47C40A-FC38-44E4-94A4-ADE794E76309}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.VisualStudio.BlazorExtension", "blazor\BlazorExtension\src\Microsoft.VisualStudio.BlazorExtension.csproj", "{9088E4E4-B855-457F-AE9E-D86709A5E1F4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.BlazorExtension", "blazor\BlazorExtension\src\Microsoft.VisualStudio.BlazorExtension.csproj", "{9088E4E4-B855-457F-AE9E-D86709A5E1F4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BB236B66-28C0-49DD-9CD4-C4673CD4E7B4}" + ProjectSection(SolutionItems) = preProject + ..\..\.editorconfig = ..\..\.editorconfig + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/Components/Components/perf/RenderTreeDiffBuilderBenchmark.cs b/src/Components/Components/perf/RenderTreeDiffBuilderBenchmark.cs index 406491e8d5..7b434ba13f 100644 --- a/src/Components/Components/perf/RenderTreeDiffBuilderBenchmark.cs +++ b/src/Components/Components/perf/RenderTreeDiffBuilderBenchmark.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Components.Performance renderer = new FakeRenderer(); // A simple component for basic tests -- this is similar to what MVC scaffolding generates - // for bootstrap3 form fields, but modified to be more Blazorey. + // for bootstrap3 form fields, but modified to be more Component-like. original = new RenderTreeBuilder(renderer); original.OpenElement(0, "div"); original.AddAttribute(1, "class", "form-group"); @@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Components.Performance modified.AddAttribute(5, "data-unvalidated", false); modified.AddContent(6, "Car"); modified.CloseElement(); - + modified.OpenElement(7, "input"); modified.AddAttribute(8, "class", "form-control"); modified.AddAttribute(9, "type", "text"); @@ -67,12 +67,12 @@ namespace Microsoft.AspNetCore.Components.Performance modified.AddAttribute(11, "data-validation-state", "invalid"); modified.AddAttribute(12, "value", "Lamborghini"); modified.CloseElement(); - + modified.OpenElement(13, "span"); modified.AddAttribute(14, "class", "text-danger field-validation-invalid"); // changed modified.AddContent(15, "No, you can't afford that."); modified.CloseElement(); - + modified.CloseElement(); } diff --git a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs index b5943df0ea..56573bdd5a 100644 --- a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs +++ b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs @@ -615,18 +615,6 @@ namespace Microsoft.AspNetCore.Components public double DeltaZ { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } } } -namespace Microsoft.AspNetCore.Components.Builder -{ - public static partial class ComponentsApplicationBuilderExtensions - { - public static void AddComponent(this Microsoft.AspNetCore.Components.Builder.IComponentsApplicationBuilder app, string domElementSelector) where TComponent : Microsoft.AspNetCore.Components.IComponent { } - } - public partial interface IComponentsApplicationBuilder - { - System.IServiceProvider Services { get; } - void AddComponent(System.Type componentType, string domElementSelector); - } -} namespace Microsoft.AspNetCore.Components.Forms { public partial class DataAnnotationsValidator : Microsoft.AspNetCore.Components.ComponentBase diff --git a/src/Components/Components/src/ComponentBase.cs b/src/Components/Components/src/ComponentBase.cs index af4a36a946..a2ea3c906b 100644 --- a/src/Components/Components/src/ComponentBase.cs +++ b/src/Components/Components/src/ComponentBase.cs @@ -1,9 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Components.RenderTree; using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Components.RenderTree; namespace Microsoft.AspNetCore.Components { diff --git a/src/Components/Components/src/ComponentResolver.cs b/src/Components/Components/src/ComponentResolver.cs index 77f47bc511..4e107da3db 100644 --- a/src/Components/Components/src/ComponentResolver.cs +++ b/src/Components/Components/src/ComponentResolver.cs @@ -14,22 +14,22 @@ namespace Microsoft.AspNetCore.Components internal static class ComponentResolver { /// - /// Lists all the types + /// Lists all the types /// /// /// public static IEnumerable ResolveComponents(Assembly appAssembly) { - var blazorAssembly = typeof(IComponent).Assembly; + var componentsAssembly = typeof(IComponent).Assembly; - return EnumerateAssemblies(appAssembly.GetName(), blazorAssembly, new HashSet(new AssemblyComparer())) + return EnumerateAssemblies(appAssembly.GetName(), componentsAssembly, new HashSet(new AssemblyComparer())) .SelectMany(a => a.ExportedTypes) .Where(t => typeof(IComponent).IsAssignableFrom(t)); } private static IEnumerable EnumerateAssemblies( AssemblyName assemblyName, - Assembly blazorAssembly, + Assembly componentAssembly, HashSet visited) { var assembly = Assembly.Load(assemblyName); @@ -40,9 +40,9 @@ namespace Microsoft.AspNetCore.Components } visited.Add(assembly); var references = assembly.GetReferencedAssemblies(); - if (!references.Any(r => string.Equals(r.FullName, blazorAssembly.FullName, StringComparison.Ordinal))) + if (!references.Any(r => string.Equals(r.FullName, componentAssembly.FullName, StringComparison.Ordinal))) { - // Avoid traversing references that don't point to blazor (like netstandard2.0) + // Avoid traversing references that don't point to Components (like netstandard2.0) yield break; } else @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Components yield return assembly; // Look at the list of transitive dependencies for more components. - foreach (var reference in references.SelectMany(r => EnumerateAssemblies(r, blazorAssembly, visited))) + foreach (var reference in references.SelectMany(r => EnumerateAssemblies(r, componentAssembly, visited))) { yield return reference; } diff --git a/src/Components/Components/src/Rendering/RendererSynchronizationContext.cs b/src/Components/Components/src/Rendering/RendererSynchronizationContext.cs index 0b8a90ae31..9a235b791f 100644 --- a/src/Components/Components/src/Rendering/RendererSynchronizationContext.cs +++ b/src/Components/Components/src/Rendering/RendererSynchronizationContext.cs @@ -163,7 +163,7 @@ namespace Microsoft.AspNetCore.Components.Rendering } // We have to block. That's the contract of Send - we don't expect this to be used - // in many scenarios in Blazor. + // in many scenarios in Components. // // Using Wait here is ok because the antecedant task will never throw. antecedant.Wait(); diff --git a/src/Components/Components/test/RendererTest.cs b/src/Components/Components/test/RendererTest.cs index 5eedeb6630..8d67ab50c9 100644 --- a/src/Components/Components/test/RendererTest.cs +++ b/src/Components/Components/test/RendererTest.cs @@ -2513,7 +2513,7 @@ namespace Microsoft.AspNetCore.Components.Test { // This represents the scenario where the same event handler is being triggered // rapidly, such as an input event while typing. It only applies to asynchronous - // batch updates, i.e., server-side Blazor. + // batch updates, i.e., server-side Components. // Sequence: // 1. The client dispatches event X twice (say) in quick succession // 2. The server receives the first instance, handles the event, and re-renders diff --git a/src/Components/Server/src/Circuits/RemoteUriHelper.cs b/src/Components/Server/src/Circuits/RemoteUriHelper.cs index c040d4efc9..447a9e93b5 100644 --- a/src/Components/Server/src/Circuits/RemoteUriHelper.cs +++ b/src/Components/Server/src/Circuits/RemoteUriHelper.cs @@ -10,7 +10,7 @@ using Interop = Microsoft.AspNetCore.Components.Browser.BrowserUriHelperInterop; namespace Microsoft.AspNetCore.Components.Server.Circuits { /// - /// A Server-Side Blazor implementation of . + /// A Server-Side Components implementation of . /// public class RemoteUriHelper : UriHelperBase { diff --git a/src/Components/Server/src/DependencyInjection/ConfigureStaticFilesOptions.cs b/src/Components/Server/src/DependencyInjection/ConfigureStaticFilesOptions.cs index 650ac46502..cfc2817587 100644 --- a/src/Components/Server/src/DependencyInjection/ConfigureStaticFilesOptions.cs +++ b/src/Components/Server/src/DependencyInjection/ConfigureStaticFilesOptions.cs @@ -44,14 +44,14 @@ namespace Microsoft.AspNetCore.Components.Server var prepareResponse = options.OnPrepareResponse; if (prepareResponse == null) { - options.OnPrepareResponse = BlazorApplicationBuilderExtensions.SetCacheHeaders; + options.OnPrepareResponse = CacheHeaderSettings.SetCacheHeaders; } else { void PrepareResponse(StaticFileResponseContext context) { prepareResponse(context); - BlazorApplicationBuilderExtensions.SetCacheHeaders(context); + CacheHeaderSettings.SetCacheHeaders(context); } options.OnPrepareResponse = PrepareResponse; diff --git a/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj b/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj index 0b5936ec14..68ad030e47 100644 --- a/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj +++ b/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj @@ -13,19 +13,23 @@ false false - + - - + - + - + + + + diff --git a/src/Components/Shared/src/CacheHeaderSettings.cs b/src/Components/Shared/src/CacheHeaderSettings.cs new file mode 100644 index 0000000000..c4d6e8a260 --- /dev/null +++ b/src/Components/Shared/src/CacheHeaderSettings.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Http; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.StaticFiles +{ + internal static class CacheHeaderSettings + { + internal static void SetCacheHeaders(StaticFileResponseContext ctx) + { + // By setting "Cache-Control: no-cache", we're allowing the browser to store + // a cached copy of the response, but telling it that it must check with the + // server for modifications (based on Etag) before using that cached copy. + // Longer term, we should generate URLs based on content hashes (at least + // for published apps) so that the browser doesn't need to make any requests + // for unchanged files. + var headers = ctx.Context.Response.GetTypedHeaders(); + if (headers.CacheControl == null) + { + headers.CacheControl = new CacheControlHeaderValue + { + NoCache = true + }; + } + } + } +} \ No newline at end of file diff --git a/src/Components/Shared/src/ComponentsApi.cs b/src/Components/Shared/src/ComponentsApi.cs deleted file mode 100644 index 7506853e30..0000000000 --- a/src/Components/Shared/src/ComponentsApi.cs +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.Components.Shared -{ - // Constants for method names used in code-generation - // Keep these in sync with the actual definitions - internal static class ComponentsApi - { - public static readonly string AssemblyName = "Microsoft.AspNetCore.Components"; - - public static class ComponentBase - { - public static readonly string Namespace = "Microsoft.AspNetCore.Components"; - public static readonly string FullTypeName = Namespace + ".ComponentBase"; - public static readonly string MetadataName = FullTypeName; - - public static readonly string BuildRenderTree = nameof(BuildRenderTree); - } - - public static class ParameterAttribute - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.ParameterAttribute"; - public static readonly string MetadataName = FullTypeName; - } - - public static class LayoutAttribute - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.Layouts.LayoutAttribute"; - } - - public static class InjectAttribute - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.InjectAttribute"; - } - - public static class IComponent - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.IComponent"; - - public static readonly string MetadataName = FullTypeName; - } - - public static class IDictionary - { - public static readonly string MetadataName = "System.Collection.IDictionary`2"; - } - - public static class RenderFragment - { - public static readonly string Namespace = "Microsoft.AspNetCore.Components"; - public static readonly string FullTypeName = Namespace + ".RenderFragment"; - public static readonly string MetadataName = FullTypeName; - } - - public static class RenderFragmentOfT - { - public static readonly string Namespace = "Microsoft.AspNetCore.Components"; - public static readonly string FullTypeName = Namespace + ".RenderFragment<>"; - public static readonly string MetadataName = Namespace + ".RenderFragment`1"; - } - - public static class RenderTreeBuilder - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder"; - - public static readonly string OpenElement = nameof(OpenElement); - - public static readonly string CloseElement = nameof(CloseElement); - - public static readonly string OpenComponent = nameof(OpenComponent); - - public static readonly string CloseComponent = nameof(CloseComponent); - - public static readonly string AddMarkupContent = nameof(AddMarkupContent); - - public static readonly string AddContent = nameof(AddContent); - - public static readonly string AddAttribute = nameof(AddAttribute); - - public static readonly string AddElementReferenceCapture = nameof(AddElementReferenceCapture); - - public static readonly string AddComponentReferenceCapture = nameof(AddComponentReferenceCapture); - - public static readonly string Clear = nameof(Clear); - - public static readonly string GetFrames = nameof(GetFrames); - - public static readonly string ChildContent = nameof(ChildContent); - } - - public static class RuntimeHelpers - { - public static readonly string TypeCheck = "Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck"; - } - - public static class RouteAttribute - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.RouteAttribute"; - } - - public static class BindElementAttribute - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.BindElementAttribute"; - } - - public static class BindInputElementAttribute - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.BindInputElementAttribute"; - } - - public static class BindMethods - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.BindMethods"; - - public static readonly string GetValue = "Microsoft.AspNetCore.Components.BindMethods.GetValue"; - - public static readonly string GetEventHandlerValue = "Microsoft.AspNetCore.Components.BindMethods.GetEventHandlerValue"; - - public static readonly string SetValueHandler = "Microsoft.AspNetCore.Components.BindMethods.SetValueHandler"; - } - - public static class EventHandlerAttribute - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.EventHandlerAttribute"; - } - - public static class ElementRef - { - public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.ElementRef"; - } - } -} diff --git a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/ServerFixture.cs b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/ServerFixture.cs index 64f44e9da9..c06aec2206 100644 --- a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/ServerFixture.cs +++ b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/ServerFixture.cs @@ -37,8 +37,16 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures private static Dictionary FindProjects() { var solutionDir = FindSolutionDir(); - return Directory.GetFiles(solutionDir, "*.csproj", SearchOption.AllDirectories) - .ToDictionary(Path.GetFileNameWithoutExtension, Path.GetDirectoryName); + + var testAssetsDirectories = new[] + { + Path.Combine(solutionDir, "test", "testassets"), + Path.Combine(solutionDir, "blazor", "testassets"), + }; + + return testAssetsDirectories + .SelectMany(d => new DirectoryInfo(d).EnumerateDirectories()) + .ToDictionary(d => d.Name, d => d.FullName); } protected static string FindSampleOrTestSitePath(string projectName) diff --git a/src/Components/test/E2ETest/Tests/ComponentRenderingTest.cs b/src/Components/test/E2ETest/Tests/ComponentRenderingTest.cs index f92a0d3f26..dc6ca816d0 100644 --- a/src/Components/test/E2ETest/Tests/ComponentRenderingTest.cs +++ b/src/Components/test/E2ETest/Tests/ComponentRenderingTest.cs @@ -318,11 +318,11 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests { var appElement = MountTestComponent(); - // NuGet packages can use Blazor's JS interop features to provide + // NuGet packages can use JS interop features to provide // .NET code access to browser APIs var showPromptButton = appElement.FindElements(By.TagName("button")).First(); showPromptButton.Click(); - + var modal = new WebDriverWait(Browser, TimeSpan.FromSeconds(3)) .Until(SwitchToAlert); modal.SendKeys("Some value from test"); @@ -330,14 +330,14 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests var promptResult = appElement.FindElement(By.TagName("strong")); WaitAssert.Equal("Some value from test", () => promptResult.Text); - // NuGet packages can also embed entire Blazor components (themselves + // NuGet packages can also embed entire components (themselves // authored as Razor files), including static content. The CSS value // here is in a .css file, so if it's correct we know that static content // file was loaded. var specialStyleDiv = appElement.FindElement(By.ClassName("special-style")); Assert.Equal("50px", specialStyleDiv.GetCssValue("padding")); - // The external Blazor components are fully functional, not just static HTML + // The external components are fully functional, not just static HTML var externalComponentButton = specialStyleDiv.FindElement(By.TagName("button")); Assert.Equal("Click me", externalComponentButton.Text); externalComponentButton.Click(); diff --git a/src/Components/test/testassets/BasicTestApp/Startup.cs b/src/Components/test/testassets/BasicTestApp/Startup.cs index 35e5ca921f..0f509b98e8 100644 --- a/src/Components/test/testassets/BasicTestApp/Startup.cs +++ b/src/Components/test/testassets/BasicTestApp/Startup.cs @@ -1,12 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Runtime.InteropServices; using Microsoft.AspNetCore.Blazor.Http; -using Microsoft.AspNetCore.Blazor.Services; using Microsoft.AspNetCore.Components.Builder; using Microsoft.Extensions.DependencyInjection; -using System; -using System.Runtime.InteropServices; namespace BasicTestApp { diff --git a/src/Components/test/testassets/ComponentsApp.App/App.cshtml b/src/Components/test/testassets/ComponentsApp.App/App.cshtml index adfe72aa7d..033dcc04b8 100644 --- a/src/Components/test/testassets/ComponentsApp.App/App.cshtml +++ b/src/Components/test/testassets/ComponentsApp.App/App.cshtml @@ -2,4 +2,4 @@ Configuring this stuff here is temporary. Later we'll move the app config into Startup.cs, and it won't be necessary to specify AppAssembly. --> - + diff --git a/src/Components/test/testassets/ComponentsApp.App/Shared/MainLayout.cshtml b/src/Components/test/testassets/ComponentsApp.App/Shared/MainLayout.cshtml index ecd956e1d1..3ec4a5afa4 100644 --- a/src/Components/test/testassets/ComponentsApp.App/Shared/MainLayout.cshtml +++ b/src/Components/test/testassets/ComponentsApp.App/Shared/MainLayout.cshtml @@ -5,9 +5,6 @@
- @*
- About -
*@
@Body diff --git a/src/Components/test/testassets/ComponentsApp.App/Startup.cs b/src/Components/test/testassets/ComponentsApp.App/Startup.cs deleted file mode 100644 index f896ae6b28..0000000000 --- a/src/Components/test/testassets/ComponentsApp.App/Startup.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Components.Builder; -using Microsoft.Extensions.DependencyInjection; - -namespace ComponentsApp.App -{ - public class Startup - { - public void ConfigureServices(IServiceCollection services) - { - } - - public void Configure(IComponentsApplicationBuilder app) - { - app.AddComponent("app"); - } - } -} diff --git a/src/Components/test/testassets/ComponentsApp.Server/ComponentsApp.Server.csproj b/src/Components/test/testassets/ComponentsApp.Server/ComponentsApp.Server.csproj index 6fa0b66dc3..19379ceb99 100644 --- a/src/Components/test/testassets/ComponentsApp.Server/ComponentsApp.Server.csproj +++ b/src/Components/test/testassets/ComponentsApp.Server/ComponentsApp.Server.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.0 diff --git a/src/Components/test/testassets/TestServer/TestServer.csproj b/src/Components/test/testassets/TestServer/TestServer.csproj index a56f986a37..289ad93655 100644 --- a/src/Components/test/testassets/TestServer/TestServer.csproj +++ b/src/Components/test/testassets/TestServer/TestServer.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.0 @@ -6,6 +6,7 @@ + diff --git a/src/Mvc/test/Mvc.FunctionalTests/BasicTests.cs b/src/Mvc/test/Mvc.FunctionalTests/BasicTests.cs index ff4ac8348a..9e63a4baaa 100644 --- a/src/Mvc/test/Mvc.FunctionalTests/BasicTests.cs +++ b/src/Mvc/test/Mvc.FunctionalTests/BasicTests.cs @@ -478,18 +478,18 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests // Act var response = await Client.GetStringAsync("Home/GetAssemblyPartData"); var assemblyParts = JsonConvert.DeserializeObject>(response); - var expected = new[] - { - "BasicWebSite", - "Microsoft.AspNetCore.Components.Server", - "Microsoft.AspNetCore.SpaServices", - "Microsoft.AspNetCore.SpaServices.Extensions", - "Microsoft.AspNetCore.Mvc.TagHelpers", - "Microsoft.AspNetCore.Mvc.Razor", - }; // Assert - Assert.Equal(expected, assemblyParts); + // + // We don't keep track the explicit list of assemblies that show up here + // because this can change as we work on the product. All we care about is + // that BasicWebSite is first, and that everything after it is a Microsoft. + Assert.True(assemblyParts.Count > 2); + Assert.Equal("BasicWebSite", assemblyParts[0]); + for (var i = 1; i < assemblyParts.Count; i++) + { + Assert.StartsWith("Microsoft.", assemblyParts[i]); + } } [Fact]