Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/aspnetcore.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPranav K <prkrishn@hotmail.com>2020-06-24 04:19:55 +0300
committerGitHub <noreply@github.com>2020-06-24 04:19:55 +0300
commitf6a6e4bd07bd4bf51c6965382156ebce22540fb7 (patch)
treea85ffe7caa2f2daafe52614fd020252a442d9af8
parentda03fe4c4872c10a63497a68b0e9bd85c1b947af (diff)
Replat blazor on net5 (#23078)
* Replat blazor on net5 * Make all e2e tests pass * Fixup * Update js files * Fixups * Fixup * Fixup * Skip globalization tests * Undo workarounds * PR feedback * Update dependencies from https://github.com/dotnet/runtime build 20200622.6 System.ComponentModel.Annotations , System.Diagnostics.DiagnosticSource , System.Diagnostics.EventLog , Microsoft.Extensions.Logging.Configuration , Microsoft.Extensions.Logging.Console , Microsoft.Extensions.Logging.Debug , Microsoft.Extensions.Logging.EventLog , Microsoft.Extensions.Logging.EventSource , Microsoft.Extensions.Logging.TraceSource , Microsoft.Extensions.Options , Microsoft.Extensions.Options.ConfigurationExtensions , Microsoft.Extensions.Options.DataAnnotations , Microsoft.Extensions.Primitives , Microsoft.Extensions.Logging.Abstractions , Microsoft.Extensions.Logging , Microsoft.Extensions.Internal.Transport , Microsoft.Extensions.Http , Microsoft.Extensions.Caching.Abstractions , Microsoft.Extensions.Caching.Memory , Microsoft.Extensions.Configuration , Microsoft.Extensions.Configuration.Abstractions , Microsoft.Extensions.Configuration.Binder , Microsoft.Extensions.Configuration.CommandLine , Microsoft.Extensions.Configuration.EnvironmentVariables , Microsoft.Extensions.Configuration.FileExtensions , Microsoft.Extensions.Configuration.Ini , Microsoft.Extensions.Configuration.Json , Microsoft.Extensions.Configuration.UserSecrets , Microsoft.Extensions.DependencyInjection , Microsoft.Extensions.DependencyInjection.Abstractions , Microsoft.Extensions.DependencyModel , Microsoft.Extensions.FileProviders.Abstractions , Microsoft.Extensions.FileProviders.Composite , Microsoft.Extensions.FileProviders.Physical , Microsoft.Extensions.FileSystemGlobbing , Microsoft.Extensions.HostFactoryResolver.Sources , Microsoft.Extensions.Hosting , Microsoft.Extensions.Hosting.Abstractions , Microsoft.Extensions.Configuration.Xml , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.Platforms , Microsoft.Win32.Registry , Microsoft.Win32.SystemEvents , Microsoft.NETCore.App.Internal , Microsoft.NETCore.App.Ref , System.Drawing.Common , System.ServiceProcess.ServiceController , System.Text.Encodings.Web , System.Text.Json , System.Threading.Channels , System.Windows.Extensions , System.Security.Principal.Windows , System.Security.Permissions , System.Security.Cryptography.Xml , System.IO.Pipelines , System.Net.Http.Json , System.Net.Http.WinHttpHandler , System.Net.WebSockets.WebSocketProtocol , System.Reflection.Metadata , System.Runtime.CompilerServices.Unsafe , System.Security.Cryptography.Cng , System.Security.Cryptography.Pkcs From Version 5.0.0-preview.7.20321.2 -> To Version 5.0.0-preview.7.20322.6 * Update js file * Fix version * Fixup Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
-rw-r--r--eng/ProjectReferences.props2
-rw-r--r--src/Components/Components.sln126
-rw-r--r--src/Components/ComponentsNoDeps.slnf5
-rw-r--r--src/Components/Directory.Build.targets13
-rw-r--r--src/Components/Web.JS/dist/Release/blazor.webassembly.js2
-rw-r--r--src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts12
-rw-r--r--src/Components/WebAssembly/Build/src/Microsoft.AspNetCore.Components.WebAssembly.Build.csproj112
-rw-r--r--src/Components/WebAssembly/Build/src/Microsoft.AspNetCore.Components.WebAssembly.Build.nuspec19
-rw-r--r--src/Components/WebAssembly/Build/src/ReferenceBlazorBuildFromSource.props27
-rw-r--r--src/Components/WebAssembly/Build/src/ReferenceFromSource.props48
-rw-r--r--src/Components/WebAssembly/Build/src/Tasks/BlazorGetFileHash.cs135
-rw-r--r--src/Components/WebAssembly/Build/src/Tasks/BlazorILLink.cs194
-rw-r--r--src/Components/WebAssembly/Build/src/Tasks/BrotliCompressBlazorApplicationFiles.cs52
-rw-r--r--src/Components/WebAssembly/Build/src/Tasks/GenerateBlazorBootJson.cs232
-rw-r--r--src/Components/WebAssembly/Build/src/Tasks/GenerateBlazorCompressionManifest.cs102
-rw-r--r--src/Components/WebAssembly/Build/src/Tasks/GenerateServiceWorkerAssetsManifest.cs82
-rw-r--r--src/Components/WebAssembly/Build/src/Tasks/GenerateTypeGranularityLinkingConfig.cs48
-rw-r--r--src/Components/WebAssembly/Build/src/Tasks/GzipCompressBlazorApplicationFiles.cs89
-rw-r--r--src/Components/WebAssembly/Build/src/Tasks/ResolveBlazorRuntimeDependencies.cs203
-rw-r--r--src/Components/WebAssembly/Build/src/build/netstandard1.0/Microsoft.AspNetCore.Components.WebAssembly.Build.props7
-rw-r--r--src/Components/WebAssembly/Build/src/build/netstandard1.0/Microsoft.AspNetCore.Components.WebAssembly.Build.targets3
-rw-r--r--src/Components/WebAssembly/Build/src/targets/All.props16
-rw-r--r--src/Components/WebAssembly/Build/src/targets/All.targets21
-rw-r--r--src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.props20
-rw-r--r--src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets489
-rw-r--r--src/Components/WebAssembly/Build/src/targets/CollationLinkerDescriptor.xml21
-rw-r--r--src/Components/WebAssembly/Build/src/targets/Compression.targets108
-rw-r--r--src/Components/WebAssembly/Build/src/targets/Publish.targets40
-rw-r--r--src/Components/WebAssembly/Build/src/targets/ServiceWorkerAssetsManifest.targets240
-rw-r--r--src/Components/WebAssembly/Build/src/targets/StaticWebAssets.props15
-rw-r--r--src/Components/WebAssembly/Build/src/targets/StaticWebAssets.targets165
-rw-r--r--src/Components/WebAssembly/Build/test/BlazorCreateRootDescriptorFileTest.cs38
-rw-r--r--src/Components/WebAssembly/Build/test/BuildIntegrationTests/Assert.cs1006
-rw-r--r--src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildCompressionTests.cs396
-rw-r--r--src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildIntegrationTest.cs361
-rw-r--r--src/Components/WebAssembly/Build/test/BuildIntegrationTests/FileThumbPrint.cs74
-rw-r--r--src/Components/WebAssembly/Build/test/BuildIntegrationTests/MSBuildProcessManager.cs284
-rw-r--r--src/Components/WebAssembly/Build/test/BuildIntegrationTests/MSBuildResult.cs28
-rw-r--r--src/Components/WebAssembly/Build/test/BuildIntegrationTests/ProjectDirectory.cs233
-rw-r--r--src/Components/WebAssembly/Build/test/BuildIntegrationTests/ProjectDirectoryTest.cs21
-rw-r--r--src/Components/WebAssembly/Build/test/BuildIntegrationTests/PwaManifestTests.cs118
-rw-r--r--src/Components/WebAssembly/Build/test/BuildIntegrationTests/TestFacts.cs26
-rw-r--r--src/Components/WebAssembly/Build/test/BuildIntegrationTests/WebAssemblyRuntimePackage.cs27
-rw-r--r--src/Components/WebAssembly/Build/test/Microsoft.AspNetCore.Components.WebAssembly.Build.Tests.csproj75
-rw-r--r--src/Components/WebAssembly/Build/test/RuntimeDependenciesResolverTest.cs181
-rw-r--r--src/Components/WebAssembly/Build/testassets/Directory.Build.props30
-rw-r--r--src/Components/WebAssembly/Build/testassets/Directory.Build.targets2
-rw-r--r--src/Components/WebAssembly/Build/testassets/blazorhosted/blazorhosted.csproj11
-rw-r--r--src/Components/WebAssembly/Build/testassets/standalone/standalone.csproj40
-rw-r--r--src/Components/WebAssembly/Compression/src/Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression.csproj10
-rw-r--r--src/Components/WebAssembly/Compression/src/Program.cs91
-rw-r--r--src/Components/WebAssembly/Compression/src/runtimeconfig.template.json3
-rw-r--r--src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj19
-rw-r--r--src/Components/WebAssembly/WebAssembly/src/build/netstandard2.0/Microsoft.AspNetCore.Components.WebAssembly.props5
-rw-r--r--src/Components/WebAssembly/testassets/HostedInAspNet.Client/HostedInAspNet.Client.csproj10
-rw-r--r--src/Components/WebAssembly/testassets/MonoSanity/MonoSanity.csproj16
-rw-r--r--src/Components/WebAssembly/testassets/MonoSanity/Program.cs27
-rw-r--r--src/Components/WebAssembly/testassets/MonoSanity/Startup.cs28
-rw-r--r--src/Components/WebAssembly/testassets/MonoSanity/wwwroot/index.html158
-rw-r--r--src/Components/WebAssembly/testassets/MonoSanity/wwwroot/loader.js128
-rw-r--r--src/Components/WebAssembly/testassets/MonoSanityClient/Examples.cs63
-rw-r--r--src/Components/WebAssembly/testassets/MonoSanityClient/InternalCalls.cs25
-rw-r--r--src/Components/WebAssembly/testassets/MonoSanityClient/MonoSanityClient.csproj13
-rw-r--r--src/Components/WebAssembly/testassets/MonoSanityClient/Program.cs15
-rw-r--r--src/Components/WebAssembly/testassets/StandaloneApp/StandaloneApp.csproj6
-rw-r--r--src/Components/WebAssembly/testassets/Wasm.Authentication.Client/Wasm.Authentication.Client.csproj7
-rw-r--r--src/Components/benchmarkapps/Wasm.Performance/TestApp/Wasm.Performance.TestApp.csproj6
-rw-r--r--src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj2
-rw-r--r--src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs2
-rw-r--r--src/Components/test/E2ETest/Tests/MonoSanityTest.cs157
-rw-r--r--src/Components/test/E2ETest/Tests/WebAssemblyAuthenticationTests.cs6
-rw-r--r--src/Components/test/E2ETest/Tests/WebAssemblyGlobalizationTest.cs6
-rw-r--r--src/Components/test/E2ETest/Tests/WebAssemblyLocalizationTest.cs2
-rw-r--r--src/Components/test/E2ETest/Tests/WebAssemblyLoggingTest.cs3
-rw-r--r--src/Components/test/E2ETest/Tests/WebAssemblyStringComparisonTest.cs2
-rw-r--r--src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj6
-rw-r--r--src/Components/test/testassets/BasicTestApp/Program.cs2
-rw-r--r--src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js2
-rw-r--r--src/Components/test/testassets/ComponentsApp.App/ComponentsApp.App.csproj3
-rw-r--r--src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj4
-rw-r--r--src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs7
-rw-r--r--src/ProjectTemplates/BlazorTemplates.Tests/Infrastructure/TemplateTests.props.in3
-rw-r--r--src/ProjectTemplates/Shared/Project.cs14
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/ComponentsWebAssembly-CSharp.Client.csproj.in6
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/ComponentsWebAssembly-CSharp.Shared.csproj.in2
-rw-r--r--src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj1
-rw-r--r--src/ProjectTemplates/test/Infrastructure/TemplateTests.props.in3
-rw-r--r--src/ProjectTemplates/test/ProjectTemplates.Tests.csproj6
-rw-r--r--src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Application.cs1
-rw-r--r--src/Razor/Microsoft.AspNetCore.Razor.Tools/src/BrotliCompressCommand.cs70
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Assert.cs73
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildIntegrationTest.cs4
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildServerIntegrationTest.cs4
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildVariables.cs2
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildWithComponents31IntegrationTest.cs2
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildWithComponentsIntegrationTest.cs8
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/DesignTimeBuildIntegrationTest.cs2
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/FIleThumbPrint.cs20
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/InitializeTestProjectAttribute.cs7
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MSBuildIntegrationTestBase.cs22
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MSBuildProcessManager.cs42
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Microsoft.NET.Sdk.Razor.IntegrationTests.csproj10
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MvcBuildIntegrationTestLegacy.cs7
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/PackIntegrationTest.cs4
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/ProjectDirectory.cs107
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/ServiceWorkerAssert.cs80
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmBuildIncrementalismTest.cs (renamed from src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildIncrementalismTest.cs)41
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmBuildIntegrationTest.cs242
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmBuildLazyLoadTest.cs173
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmCompressionTests.cs165
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmPublishIntegrationTest.cs (renamed from src/Components/WebAssembly/Build/test/BuildIntegrationTests/PublishIntegrationTest.cs)461
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmPwaManifestTests.cs211
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/AssetsManifestFile.cs33
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/BlazorReadSatelliteAssemblyFile.cs (renamed from src/Components/WebAssembly/Build/src/Tasks/BlazorReadSatelliteAssemblyFile.cs)2
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/BlazorWriteSatelliteAssemblyFile.cs (renamed from src/Components/WebAssembly/Build/src/Tasks/BlazorWriteSatelliteAssemblyFile.cs)2
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/BootJsonData.cs85
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/BrotliCompress.cs99
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/CreateBlazorTrimmerRootDescriptorFile.cs (renamed from src/Components/WebAssembly/Build/src/Tasks/BlazorCreateRootDescriptorFile.cs)37
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/GenerateBlazorWebAssemblyBootJson.cs155
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/GenerateServiceWorkerAssetsManifest.cs97
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/Microsoft.NET.Sdk.Razor.csproj2
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/BlazorWasm.web.config (renamed from src/Components/WebAssembly/Build/src/targets/Standalone.Web.config)0
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/LinkerWorkaround.xml (renamed from src/Components/WebAssembly/Build/src/targets/BuiltInBclLinkerDescriptor.xml)8
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.CodeGeneration.targets6
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Component.targets2
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Components.ServiceWorkerAssetsManifest.targets166
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Components.Wasm.targets490
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.StaticWebAssets.targets6
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.props3
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.props2
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets4
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/test/BlazorReadSatelliteAssemblyFileTest.cs (renamed from src/Components/WebAssembly/Build/test/BlazorReadSatelliteAssemblyFileTest.cs)3
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/test/GenerateBlazorBootJsonTest.cs (renamed from src/Components/WebAssembly/Build/test/GenerateBlazorBootJsonTest.cs)83
-rw-r--r--src/Razor/Microsoft.NET.Sdk.Razor/test/GenerateStaticWebAssetsPropsFileTest.cs1
-rw-r--r--src/Razor/test/testassets/Directory.Build.props5
-rw-r--r--src/Razor/test/testassets/LinkBaseToWebRoot/js/LinkedScript.js (renamed from src/Components/WebAssembly/Build/testassets/LinkBaseToWebRoot/js/LinkedScript.js)0
-rw-r--r--src/Razor/test/testassets/RestoreTestProjects/RestoreTestProjects.csproj3
-rw-r--r--src/Razor/test/testassets/SimpleMvc21/SimpleMvc21.csproj1
-rw-r--r--src/Razor/test/testassets/blazor.webassembly.js1
-rw-r--r--src/Razor/test/testassets/blazorhosted-rid/Program.cs12
-rw-r--r--src/Razor/test/testassets/blazorhosted-rid/blazorhosted-rid.csproj22
-rw-r--r--src/Razor/test/testassets/blazorhosted/Program.cs (renamed from src/Components/WebAssembly/Build/testassets/blazorhosted/Program.cs)0
-rw-r--r--src/Razor/test/testassets/blazorhosted/blazorhosted.csproj12
-rw-r--r--src/Razor/test/testassets/blazorwasm/App.razor (renamed from src/Components/WebAssembly/Build/testassets/standalone/App.razor)0
-rw-r--r--src/Razor/test/testassets/blazorwasm/LinkToWebRoot/css/app.css (renamed from src/Components/WebAssembly/Build/testassets/standalone/LinkToWebRoot/css/app.css)0
-rw-r--r--src/Razor/test/testassets/blazorwasm/Pages/Index.razor (renamed from src/Components/WebAssembly/Build/testassets/standalone/Pages/Index.razor)0
-rw-r--r--src/Razor/test/testassets/blazorwasm/Program.cs (renamed from src/Components/WebAssembly/Build/testassets/standalone/Program.cs)1
-rw-r--r--src/Razor/test/testassets/blazorwasm/Resources.ja.resx.txt (renamed from src/Components/WebAssembly/Build/testassets/standalone/Resources.ja.resx.txt)0
-rw-r--r--src/Razor/test/testassets/blazorwasm/_Imports.razor (renamed from src/Components/WebAssembly/Build/testassets/standalone/_Imports.razor)0
-rw-r--r--src/Razor/test/testassets/blazorwasm/blazorwasm.csproj45
-rw-r--r--src/Razor/test/testassets/blazorwasm/wwwroot/Fake-License.txt (renamed from src/Components/WebAssembly/Build/testassets/standalone/wwwroot/Fake-License.txt)0
-rw-r--r--src/Razor/test/testassets/blazorwasm/wwwroot/css/app.css (renamed from src/Components/WebAssembly/Build/testassets/standalone/wwwroot/css/app.css)0
-rw-r--r--src/Razor/test/testassets/blazorwasm/wwwroot/index.html (renamed from src/Components/WebAssembly/Build/testassets/standalone/wwwroot/index.html)0
-rw-r--r--src/Razor/test/testassets/blazorwasm/wwwroot/serviceworkers/my-prod-service-worker.js (renamed from src/Components/WebAssembly/Build/testassets/standalone/wwwroot/serviceworkers/my-prod-service-worker.js)0
-rw-r--r--src/Razor/test/testassets/blazorwasm/wwwroot/serviceworkers/my-service-worker.js (renamed from src/Components/WebAssembly/Build/testassets/standalone/wwwroot/serviceworkers/my-service-worker.js)0
-rw-r--r--src/Razor/test/testassets/classlibrarywithsatelliteassemblies/Class1.cs (renamed from src/Components/WebAssembly/Build/testassets/classlibrarywithsatelliteassemblies/Class1.cs)0
-rw-r--r--src/Razor/test/testassets/classlibrarywithsatelliteassemblies/Resources.es-ES.resx (renamed from src/Components/WebAssembly/Build/testassets/classlibrarywithsatelliteassemblies/Resources.es-ES.resx)0
-rw-r--r--src/Razor/test/testassets/classlibrarywithsatelliteassemblies/classlibrarywithsatelliteassemblies.csproj (renamed from src/Components/WebAssembly/Build/testassets/classlibrarywithsatelliteassemblies/classlibrarywithsatelliteassemblies.csproj)1
-rw-r--r--src/Razor/test/testassets/razorclasslibrary/Class1.cs (renamed from src/Components/WebAssembly/Build/testassets/razorclasslibrary/Class1.cs)0
-rw-r--r--src/Razor/test/testassets/razorclasslibrary/RazorClassLibrary.csproj (renamed from src/Components/WebAssembly/Build/testassets/razorclasslibrary/RazorClassLibrary.csproj)1
-rw-r--r--src/Razor/test/testassets/razorclasslibrary/wwwroot/styles.css (renamed from src/Components/WebAssembly/Build/testassets/razorclasslibrary/wwwroot/styles.css)0
-rw-r--r--src/Razor/test/testassets/razorclasslibrary/wwwroot/wwwroot/exampleJsInterop.js (renamed from src/Components/WebAssembly/Build/testassets/razorclasslibrary/wwwroot/wwwroot/exampleJsInterop.js)0
162 files changed, 2913 insertions, 6703 deletions
diff --git a/eng/ProjectReferences.props b/eng/ProjectReferences.props
index 825685a528..dd12efa35e 100644
--- a/eng/ProjectReferences.props
+++ b/eng/ProjectReferences.props
@@ -64,8 +64,6 @@
<ProjectReferenceProvider Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" ProjectPath="$(RepoRoot)src\SignalR\server\StackExchangeRedis\src\Microsoft.AspNetCore.SignalR.StackExchangeRedis.csproj" />
<ProjectReferenceProvider Include="Ignitor" ProjectPath="$(RepoRoot)src\Components\Ignitor\src\Ignitor.csproj" />
<ProjectReferenceProvider Include="Microsoft.Authentication.WebAssembly.Msal" ProjectPath="$(RepoRoot)src\Components\WebAssembly\Authentication.Msal\src\Microsoft.Authentication.WebAssembly.Msal.csproj" />
- <ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebAssembly.Build" ProjectPath="$(RepoRoot)src\Components\WebAssembly\Build\src\Microsoft.AspNetCore.Components.WebAssembly.Build.csproj" />
- <ProjectReferenceProvider Include="blazor-brotli" ProjectPath="$(RepoRoot)src\Components\WebAssembly\Compression\src\Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression.csproj" />
<ProjectReferenceProvider Include="Microsoft.JSInterop.WebAssembly" ProjectPath="$(RepoRoot)src\Components\WebAssembly\JSInterop\src\Microsoft.JSInterop.WebAssembly.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebAssembly.Server" ProjectPath="$(RepoRoot)src\Components\WebAssembly\Server\src\Microsoft.AspNetCore.Components.WebAssembly.Server.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" ProjectPath="$(RepoRoot)src\Components\WebAssembly\WebAssembly.Authentication\src\Microsoft.AspNetCore.Components.WebAssembly.Authentication.csproj" />
diff --git a/src/Components/Components.sln b/src/Components/Components.sln
index 156f3870d8..722c3a4ea1 100644
--- a/src/Components/Components.sln
+++ b/src/Components/Components.sln
@@ -15,24 +15,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Compon
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.WebAssembly.Tests", "WebAssembly\WebAssembly\test\Microsoft.AspNetCore.Components.WebAssembly.Tests.csproj", "{958AD6D2-174B-4B5B-BEFC-FA64B5159334}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.WebAssembly.Build", "WebAssembly\Build\src\Microsoft.AspNetCore.Components.WebAssembly.Build.csproj", "{E8AD67A4-77D3-4B85-AE19-4711388B62B1}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.WebAssembly.Build.Tests", "WebAssembly\Build\test\Microsoft.AspNetCore.Components.WebAssembly.Build.Tests.csproj", "{E38FDBB0-08C1-444E-A449-69C8A59D721B}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.WebAssembly.DevServer", "WebAssembly\DevServer\src\Microsoft.AspNetCore.Components.WebAssembly.DevServer.csproj", "{A6C8050D-7C18-4585-ADCF-833AC1765847}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.WebAssembly.Server", "WebAssembly\Server\src\Microsoft.AspNetCore.Components.WebAssembly.Server.csproj", "{A4859630-F9F7-4F5C-9FF3-6C013D7C58FA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{A7ABAC29-F73F-456D-AE54-46842CFC2E10}"
+ ProjectSection(SolutionItems) = preProject
+ WebAssembly\testassets\Wasm.Authentication.Server\Wasm.Authentication.Server.csproj = WebAssembly\testassets\Wasm.Authentication.Server\Wasm.Authentication.Server.csproj
+ EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostedInAspNet.Client", "WebAssembly\testassets\HostedInAspNet.Client\HostedInAspNet.Client.csproj", "{FD37F740-A654-4117-BFB6-9112CE4C1D3B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostedInAspNet.Server", "WebAssembly\testassets\HostedInAspNet.Server\HostedInAspNet.Server.csproj", "{C1E2C117-BE47-4E29-94B3-753262D97A5C}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoSanity", "WebAssembly\testassets\MonoSanity\MonoSanity.csproj", "{F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoSanityClient", "WebAssembly\testassets\MonoSanityClient\MonoSanityClient.csproj", "{1C4BF2D3-44A8-4A71-B031-15B983663CB0}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StandaloneApp", "WebAssembly\testassets\StandaloneApp\StandaloneApp.csproj", "{C0FFB29E-4696-4875-9039-E5FA1AC5A42A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{A27FF193-195B-4474-8E6C-840B2E339373}"
@@ -244,16 +239,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Performance.TestApp",
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebAssembly", "WebAssembly", "{346EC9B8-BF36-4A5E-A1A3-77879931713A}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{1FA95650-E56E-470A-82A3-BC6572E4D6CD}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.WebAssembly.Server.Tests", "WebAssembly\Server\test\Microsoft.AspNetCore.Components.WebAssembly.Server.Tests.csproj", "{3D0ED658-9DAC-4066-A587-795321FA1C98}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{42E3C95D-A41E-4E14-96FD-AAE8F340FD7E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Authentication.WebAssembly.Msal", "WebAssembly\Authentication.Msal\src\Microsoft.Authentication.WebAssembly.Msal.csproj", "{4B4E4247-7BBF-444E-9737-407D34821D70}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression", "WebAssembly\Compression\src\Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression.csproj", "{1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.WebAssembly.DebugProxy", "WebAssembly\DebugProxy\src\Microsoft.AspNetCore.Components.WebAssembly.DebugProxy.csproj", "{B118AE2F-8D1D-413F-BC5D-060DF7CB707D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DevServer", "DevServer", "{C6B58D53-04E2-4D65-B445-B510A3CB7569}"
@@ -268,6 +259,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Authentication", "Authentic
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.WebAssembly.HttpHandler", "WebAssembly\WebAssemblyHttpHandler\src\Microsoft.AspNetCore.Components.WebAssembly.HttpHandler.csproj", "{031AD67E-DDDE-4A20-874A-8D0A791C6F4C}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Authentication.Client", "WebAssembly\testassets\Wasm.Authentication.Client\Wasm.Authentication.Client.csproj", "{5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Authentication.Shared", "WebAssembly\testassets\Wasm.Authentication.Shared\Wasm.Authentication.Shared.csproj", "{630D5388-7A2F-42DD-9154-1F62A18CBB69}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.JSInterop", "..\JSInterop\Microsoft.JSInterop\src\Microsoft.JSInterop.csproj", "{A062ACCE-AB0D-4569-9548-4BC0D9A9174B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -326,30 +323,6 @@ Global
{958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Release|x64.Build.0 = Release|Any CPU
{958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Release|x86.ActiveCfg = Release|Any CPU
{958AD6D2-174B-4B5B-BEFC-FA64B5159334}.Release|x86.Build.0 = Release|Any CPU
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Debug|x64.ActiveCfg = Debug|Any CPU
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Debug|x64.Build.0 = Debug|Any CPU
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Debug|x86.ActiveCfg = Debug|Any CPU
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Debug|x86.Build.0 = Debug|Any CPU
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Release|Any CPU.Build.0 = Release|Any CPU
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Release|x64.ActiveCfg = Release|Any CPU
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Release|x64.Build.0 = Release|Any CPU
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Release|x86.ActiveCfg = Release|Any CPU
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1}.Release|x86.Build.0 = Release|Any CPU
- {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Debug|x64.ActiveCfg = Debug|Any CPU
- {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Debug|x64.Build.0 = Debug|Any CPU
- {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Debug|x86.ActiveCfg = Debug|Any CPU
- {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Debug|x86.Build.0 = Debug|Any CPU
- {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Release|Any CPU.Build.0 = Release|Any CPU
- {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Release|x64.ActiveCfg = Release|Any CPU
- {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Release|x64.Build.0 = Release|Any CPU
- {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Release|x86.ActiveCfg = Release|Any CPU
- {E38FDBB0-08C1-444E-A449-69C8A59D721B}.Release|x86.Build.0 = Release|Any CPU
{A6C8050D-7C18-4585-ADCF-833AC1765847}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A6C8050D-7C18-4585-ADCF-833AC1765847}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A6C8050D-7C18-4585-ADCF-833AC1765847}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -398,30 +371,6 @@ Global
{C1E2C117-BE47-4E29-94B3-753262D97A5C}.Release|x64.Build.0 = Release|Any CPU
{C1E2C117-BE47-4E29-94B3-753262D97A5C}.Release|x86.ActiveCfg = Release|Any CPU
{C1E2C117-BE47-4E29-94B3-753262D97A5C}.Release|x86.Build.0 = Release|Any CPU
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Debug|x64.ActiveCfg = Debug|Any CPU
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Debug|x64.Build.0 = Debug|Any CPU
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Debug|x86.Build.0 = Debug|Any CPU
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Release|Any CPU.Build.0 = Release|Any CPU
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Release|x64.ActiveCfg = Release|Any CPU
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Release|x64.Build.0 = Release|Any CPU
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Release|x86.ActiveCfg = Release|Any CPU
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E}.Release|x86.Build.0 = Release|Any CPU
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Debug|x64.ActiveCfg = Debug|Any CPU
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Debug|x64.Build.0 = Debug|Any CPU
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Debug|x86.ActiveCfg = Debug|Any CPU
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Debug|x86.Build.0 = Debug|Any CPU
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Release|Any CPU.Build.0 = Release|Any CPU
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Release|x64.ActiveCfg = Release|Any CPU
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Release|x64.Build.0 = Release|Any CPU
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Release|x86.ActiveCfg = Release|Any CPU
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0}.Release|x86.Build.0 = Release|Any CPU
{C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C0FFB29E-4696-4875-9039-E5FA1AC5A42A}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -1526,18 +1475,6 @@ Global
{4B4E4247-7BBF-444E-9737-407D34821D70}.Release|x64.Build.0 = Release|Any CPU
{4B4E4247-7BBF-444E-9737-407D34821D70}.Release|x86.ActiveCfg = Release|Any CPU
{4B4E4247-7BBF-444E-9737-407D34821D70}.Release|x86.Build.0 = Release|Any CPU
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}.Debug|x64.ActiveCfg = Debug|Any CPU
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}.Debug|x64.Build.0 = Debug|Any CPU
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}.Debug|x86.ActiveCfg = Debug|Any CPU
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}.Debug|x86.Build.0 = Debug|Any CPU
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}.Release|Any CPU.Build.0 = Release|Any CPU
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}.Release|x64.ActiveCfg = Release|Any CPU
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}.Release|x64.Build.0 = Release|Any CPU
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}.Release|x86.ActiveCfg = Release|Any CPU
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE}.Release|x86.Build.0 = Release|Any CPU
{B118AE2F-8D1D-413F-BC5D-060DF7CB707D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B118AE2F-8D1D-413F-BC5D-060DF7CB707D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B118AE2F-8D1D-413F-BC5D-060DF7CB707D}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -1598,6 +1535,42 @@ Global
{031AD67E-DDDE-4A20-874A-8D0A791C6F4C}.Release|x64.Build.0 = Release|Any CPU
{031AD67E-DDDE-4A20-874A-8D0A791C6F4C}.Release|x86.ActiveCfg = Release|Any CPU
{031AD67E-DDDE-4A20-874A-8D0A791C6F4C}.Release|x86.Build.0 = Release|Any CPU
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}.Debug|x64.Build.0 = Debug|Any CPU
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}.Debug|x86.Build.0 = Debug|Any CPU
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}.Release|x64.ActiveCfg = Release|Any CPU
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}.Release|x64.Build.0 = Release|Any CPU
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}.Release|x86.ActiveCfg = Release|Any CPU
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0}.Release|x86.Build.0 = Release|Any CPU
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69}.Debug|x64.Build.0 = Debug|Any CPU
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69}.Debug|x86.Build.0 = Debug|Any CPU
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69}.Release|Any CPU.Build.0 = Release|Any CPU
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69}.Release|x64.ActiveCfg = Release|Any CPU
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69}.Release|x64.Build.0 = Release|Any CPU
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69}.Release|x86.ActiveCfg = Release|Any CPU
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69}.Release|x86.Build.0 = Release|Any CPU
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B}.Debug|x64.Build.0 = Debug|Any CPU
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B}.Debug|x86.Build.0 = Debug|Any CPU
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B}.Release|x64.ActiveCfg = Release|Any CPU
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B}.Release|x64.Build.0 = Release|Any CPU
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B}.Release|x86.ActiveCfg = Release|Any CPU
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1607,15 +1580,11 @@ Global
{F000C49D-3857-42A4-918D-DA4C08691FE2} = {E059A46B-56E3-41E2-83F4-B5D180056F3B}
{641922CD-E6F5-41E7-A085-EE07C2A7328D} = {346EC9B8-BF36-4A5E-A1A3-77879931713A}
{958AD6D2-174B-4B5B-BEFC-FA64B5159334} = {346EC9B8-BF36-4A5E-A1A3-77879931713A}
- {E8AD67A4-77D3-4B85-AE19-4711388B62B1} = {1FA95650-E56E-470A-82A3-BC6572E4D6CD}
- {E38FDBB0-08C1-444E-A449-69C8A59D721B} = {1FA95650-E56E-470A-82A3-BC6572E4D6CD}
{A6C8050D-7C18-4585-ADCF-833AC1765847} = {C6B58D53-04E2-4D65-B445-B510A3CB7569}
{A4859630-F9F7-4F5C-9FF3-6C013D7C58FA} = {42E3C95D-A41E-4E14-96FD-AAE8F340FD7E}
{A7ABAC29-F73F-456D-AE54-46842CFC2E10} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
{FD37F740-A654-4117-BFB6-9112CE4C1D3B} = {A7ABAC29-F73F-456D-AE54-46842CFC2E10}
{C1E2C117-BE47-4E29-94B3-753262D97A5C} = {A7ABAC29-F73F-456D-AE54-46842CFC2E10}
- {F16C1A7C-A2BD-4EB1-8BC8-23B1375F3B9E} = {A7ABAC29-F73F-456D-AE54-46842CFC2E10}
- {1C4BF2D3-44A8-4A71-B031-15B983663CB0} = {A7ABAC29-F73F-456D-AE54-46842CFC2E10}
{C0FFB29E-4696-4875-9039-E5FA1AC5A42A} = {A7ABAC29-F73F-456D-AE54-46842CFC2E10}
{3B1A56F8-B3E0-4F33-A717-50BDD4FBE12E} = {A27FF193-195B-4474-8E6C-840B2E339373}
{35A8AE1D-ED82-485E-A8E6-A357B3CB31B3} = {3D9B9B2C-E379-41BD-83D4-2E099FBDA107}
@@ -1709,11 +1678,9 @@ Global
{CA9948CA-B3FA-4C2E-A726-5E47BAD19457} = {F65EFF0F-ACF3-46BD-9A8F-CDA94AF1885A}
{97EA0A7D-FE5E-47D1-ADDC-4BFD702F55AB} = {F65EFF0F-ACF3-46BD-9A8F-CDA94AF1885A}
{346EC9B8-BF36-4A5E-A1A3-77879931713A} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
- {1FA95650-E56E-470A-82A3-BC6572E4D6CD} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
{3D0ED658-9DAC-4066-A587-795321FA1C98} = {42E3C95D-A41E-4E14-96FD-AAE8F340FD7E}
{42E3C95D-A41E-4E14-96FD-AAE8F340FD7E} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
{4B4E4247-7BBF-444E-9737-407D34821D70} = {81250121-9B43-40B1-BF11-CE4458F2676C}
- {1A4C96E8-3FAF-48FB-9F3C-068FAAAB3FEE} = {1FA95650-E56E-470A-82A3-BC6572E4D6CD}
{B118AE2F-8D1D-413F-BC5D-060DF7CB707D} = {C6B58D53-04E2-4D65-B445-B510A3CB7569}
{C6B58D53-04E2-4D65-B445-B510A3CB7569} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
{8FDD9F2E-B940-4A5F-83FD-5486D0853D76} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
@@ -1721,6 +1688,9 @@ Global
{6B0D6C08-FC30-4822-9464-4D24FF4CDC17} = {81250121-9B43-40B1-BF11-CE4458F2676C}
{81250121-9B43-40B1-BF11-CE4458F2676C} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
{031AD67E-DDDE-4A20-874A-8D0A791C6F4C} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF}
+ {5F12F7B9-70BE-48F6-922A-3A1E87EE6BF0} = {A7ABAC29-F73F-456D-AE54-46842CFC2E10}
+ {630D5388-7A2F-42DD-9154-1F62A18CBB69} = {A7ABAC29-F73F-456D-AE54-46842CFC2E10}
+ {A062ACCE-AB0D-4569-9548-4BC0D9A9174B} = {2FC10057-7A0A-4E34-8302-879925BC0102}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CC3C47E1-AD1A-4619-9CD3-E08A0148E5CE}
diff --git a/src/Components/ComponentsNoDeps.slnf b/src/Components/ComponentsNoDeps.slnf
index 2a45ec68c9..0484ef907c 100644
--- a/src/Components/ComponentsNoDeps.slnf
+++ b/src/Components/ComponentsNoDeps.slnf
@@ -17,9 +17,6 @@
"Server\\src\\Microsoft.AspNetCore.Components.Server.csproj",
"Server\\test\\Microsoft.AspNetCore.Components.Server.Tests.csproj",
"WebAssembly\\Authentication.Msal\\src\\Microsoft.Authentication.WebAssembly.Msal.csproj",
- "WebAssembly\\Build\\src\\Microsoft.AspNetCore.Components.WebAssembly.Build.csproj",
- "WebAssembly\\Build\\test\\Microsoft.AspNetCore.Components.WebAssembly.Build.Tests.csproj",
- "WebAssembly\\Compression\\src\\Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression.csproj",
"WebAssembly\\DebugProxy\\src\\Microsoft.AspNetCore.Components.WebAssembly.DebugProxy.csproj",
"WebAssembly\\DevServer\\src\\Microsoft.AspNetCore.Components.WebAssembly.DevServer.csproj",
"WebAssembly\\JSInterop\\src\\Microsoft.JSInterop.WebAssembly.csproj",
@@ -32,8 +29,6 @@
"WebAssembly\\WebAssembly\\test\\Microsoft.AspNetCore.Components.WebAssembly.Tests.csproj",
"WebAssembly\\testassets\\HostedInAspNet.Client\\HostedInAspNet.Client.csproj",
"WebAssembly\\testassets\\HostedInAspNet.Server\\HostedInAspNet.Server.csproj",
- "WebAssembly\\testassets\\MonoSanityClient\\MonoSanityClient.csproj",
- "WebAssembly\\testassets\\MonoSanity\\MonoSanity.csproj",
"WebAssembly\\testassets\\StandaloneApp\\StandaloneApp.csproj",
"Web\\src\\Microsoft.AspNetCore.Components.Web.csproj",
"Web\\test\\Microsoft.AspNetCore.Components.Web.Tests.csproj",
diff --git a/src/Components/Directory.Build.targets b/src/Components/Directory.Build.targets
index 9a5acfd3e6..1ecdb38eaf 100644
--- a/src/Components/Directory.Build.targets
+++ b/src/Components/Directory.Build.targets
@@ -1,9 +1,18 @@
<Project>
+ <PropertyGroup Condition="'$(UseBlazorWebAssembly)' == 'true'">
+ <BlazorWebAssemblyJSPath>$(RepoRoot)src\Components\Web.JS\dist\$(Configuration)\blazor.webassembly.js</BlazorWebAssemblyJSPath>
+ <BlazorWebAssemblyJSMapPath>$(BlazorWebAssemblyJSPath).map</BlazorWebAssemblyJSMapPath>
+
+ <_BlazorDevServerPath>$(RepoRoot)src/Components/WebAssembly/DevServer/src/bin/$(Configuration)/$(DefaultNetCoreTargetFramework)/blazor-devserver.dll</_BlazorDevServerPath>
+ <RunCommand>dotnet</RunCommand>
+ <RunArguments>exec &quot;$(_BlazorDevServerPath)&quot; serve --applicationpath &quot;$(TargetPath)&quot; $(AdditionalRunArguments)</RunArguments>
+ </PropertyGroup>
+
<ItemGroup>
<!-- Add a project dependency without reference output assemblies to enforce build order -->
<!-- Applying workaround for https://github.com/microsoft/msbuild/issues/2661 and https://github.com/dotnet/sdk/issues/952 -->
<ProjectReference
- Condition="'$(ReferenceBlazorBuildLocally)' == 'true' and '$(BuildNodeJS)' != 'false' and '$(BuildingInsideVisualStudio)' != 'true'"
+ Condition="'$(UseBlazorWebAssembly)' == 'true' and '$(BuildNodeJS)' != 'false' and '$(BuildingInsideVisualStudio)' != 'true'"
Include="$(RepoRoot)src\Components\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj"
ReferenceOutputAssemblies="false"
SkipGetTargetFrameworkProperties="true"
@@ -11,8 +20,6 @@
Private="false" />
</ItemGroup>
- <Import Project="WebAssembly\Build\src\ReferenceFromSource.props" Condition="'$(ReferenceBlazorBuildLocally)' == 'true'" />
-
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, Directory.Build.targets))\Directory.Build.targets" />
<ItemGroup Condition="'$(FixupWebAssemblyHttpHandlerReference)' == 'true'">
diff --git a/src/Components/Web.JS/dist/Release/blazor.webassembly.js b/src/Components/Web.JS/dist/Release/blazor.webassembly.js
index a04cf089d7..59c0e5f467 100644
--- a/src/Components/Web.JS/dist/Release/blazor.webassembly.js
+++ b/src/Components/Web.JS/dist/Release/blazor.webassembly.js
@@ -1 +1 @@
-!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=43)}([,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e){window.DotNet=e;var t=[],n={},r={},o=1,a=null;function i(e){t.push(e)}function u(e,t,n,r){var o=c();if(o.invokeDotNetFromJS){var a=JSON.stringify(r,m),i=o.invokeDotNetFromJS(e,t,n,a);return i?f(i):null}throw new Error("The current dispatcher does not support synchronous calls from JS to .NET. Use invokeMethodAsync instead.")}function s(e,t,r,a){if(e&&r)throw new Error("For instance method calls, assemblyName should be null. Received '"+e+"'.");var i=o++,u=new Promise((function(e,t){n[i]={resolve:e,reject:t}}));try{var s=JSON.stringify(a,m);c().beginInvokeDotNetFromJS(i,e,t,r,s)}catch(e){l(i,!1,e)}return u}function c(){if(null!==a)return a;throw new Error("No .NET call dispatcher has been set.")}function l(e,t,r){if(!n.hasOwnProperty(e))throw new Error("There is no pending async call with ID "+e+".");var o=n[e];delete n[e],t?o.resolve(r):o.reject(r)}function f(e){return e?JSON.parse(e,(function(e,n){return t.reduce((function(t,n){return n(e,t)}),n)})):null}function d(e){return e instanceof Error?e.message+"\n"+e.stack:e?e.toString():"null"}function p(e){if(r.hasOwnProperty(e))return r[e];var t,n=window,o="window";if(e.split(".").forEach((function(e){if(!(e in n))throw new Error("Could not find '"+e+"' in '"+o+"'.");t=n,n=n[e],o+="."+e})),n instanceof Function)return n=n.bind(t),r[e]=n,n;throw new Error("The value '"+o+"' is not a function.")}e.attachDispatcher=function(e){a=e},e.attachReviver=i,e.invokeMethod=function(e,t){for(var n=[],r=2;r<arguments.length;r++)n[r-2]=arguments[r];return u(e,t,null,n)},e.invokeMethodAsync=function(e,t){for(var n=[],r=2;r<arguments.length;r++)n[r-2]=arguments[r];return s(e,t,null,n)},e.jsCallDispatcher={findJSFunction:p,invokeJSFromDotNet:function(e,t){var n=p(e).apply(null,f(t));return null==n?null:JSON.stringify(n,m)},beginInvokeJSFromDotNet:function(e,t,n){var r=new Promise((function(e){e(p(t).apply(null,f(n)))}));e&&r.then((function(t){return c().endInvokeJSFromDotNet(e,!0,JSON.stringify([e,!0,t],m))}),(function(t){return c().endInvokeJSFromDotNet(e,!1,JSON.stringify([e,!1,d(t)]))}))},endInvokeDotNetFromJS:function(e,t,n){var r=t?n:new Error(n);l(parseInt(e),t,r)}};var h=function(){function e(e){this._id=e}return e.prototype.invokeMethod=function(e){for(var t=[],n=1;n<arguments.length;n++)t[n-1]=arguments[n];return u(null,e,this._id,t)},e.prototype.invokeMethodAsync=function(e){for(var t=[],n=1;n<arguments.length;n++)t[n-1]=arguments[n];return s(null,e,this._id,t)},e.prototype.dispose=function(){s(null,"__Dispose",this._id,null).catch((function(e){return console.error(e)}))},e.prototype.serializeAsArg=function(){return{__dotNetObject:this._id}},e}();function m(e,t){return t instanceof h?t.serializeAsArg():t}i((function(e,t){return t&&"object"==typeof t&&t.hasOwnProperty("__dotNetObject")?new h(t.__dotNetObject):t}))}(t.DotNet||(t.DotNet={}))},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(23),n(17);var r=n(24),o=n(12),a={},i=!1;function u(e,t,n){var o=a[e];o||(o=a[e]=new r.BrowserRenderer(e)),o.attachRootComponentToLogicalElement(n,t)}t.attachRootComponentToLogicalElement=u,t.attachRootComponentToElement=function(e,t,n){var r=document.querySelector(e);if(!r)throw new Error("Could not find any element matching selector '"+e+"'.");u(n||0,o.toLogicalElement(r,!0),t)},t.renderBatch=function(e,t){var n=a[e];if(!n)throw new Error("There is no browser renderer with ID "+e+".");for(var r=t.arrayRangeReader,o=t.updatedComponents(),u=r.values(o),s=r.count(o),c=t.referenceFrames(),l=r.values(c),f=t.diffReader,d=0;d<s;d++){var p=t.updatedComponentsEntry(u,d),h=f.componentId(p),m=f.edits(p);n.updateComponent(t,h,m,l)}var v=t.disposedComponentIds(),y=r.values(v),b=r.count(v);for(d=0;d<b;d++){h=t.disposedComponentIdsEntry(y,d);n.disposeComponent(h)}var g=t.disposedEventHandlerIds(),w=r.values(g),E=r.count(g);for(d=0;d<E;d++){var _=t.disposedEventHandlerIdsEntry(w,d);n.disposeEventHandler(_)}i&&(i=!1,window.scrollTo&&window.scrollTo(0,0))},t.resetScrollAfterNextBatch=function(){i=!0}},,,function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}};Object.defineProperty(t,"__esModule",{value:!0}),n(3);var a,i=n(4),u=!1,s=!1,c=null;function l(e,t,n){void 0===n&&(n=!1);var r=p(e);if(!t&&h(r))f(r,!1,n);else if(t&&location.href===e){var o=e+"?";history.replaceState(null,"",o),location.replace(e)}else n?history.replaceState(null,"",r):location.href=e}function f(e,t,n){void 0===n&&(n=!1),i.resetScrollAfterNextBatch(),n?history.replaceState(null,"",e):history.pushState(null,"",e),d(t)}function d(e){return r(this,void 0,void 0,(function(){return o(this,(function(t){switch(t.label){case 0:return c?[4,c(location.href,e)]:[3,2];case 1:t.sent(),t.label=2;case 2:return[2]}}))}))}function p(e){return(a=a||document.createElement("a")).href=e,a.href}function h(e){var t,n=(t=document.baseURI).substr(0,t.lastIndexOf("/")+1);return e.startsWith(n)}t.internalFunctions={listenForNavigationEvents:function(e){if(c=e,s)return;s=!0,window.addEventListener("popstate",(function(){return d(!1)}))},enableNavigationInterception:function(){u=!0},navigateTo:l,getBaseURI:function(){return document.baseURI},getLocationHref:function(){return location.href}},t.attachToEventDelegator=function(e){e.notifyAfterClick((function(e){if(u&&0===e.button&&!function(e){return e.ctrlKey||e.shiftKey||e.altKey||e.metaKey}(e)&&!e.defaultPrevented){var t=function e(t,n){return t?t.tagName===n?t:e(t.parentElement,n):null}(e.target,"A");if(t&&t.hasAttribute("href")){var n=t.getAttribute("target");if(!(!n||"_self"===n))return;var r=p(t.getAttribute("href"));h(r)&&(e.preventDefault(),f(r,!0))}}}))},t.navigateTo=l,t.toAbsoluteUri=p},,,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=p("_blazorLogicalChildren"),o=p("_blazorLogicalParent"),a=p("_blazorLogicalEnd");function i(e,t){if(e.childNodes.length>0&&!t)throw new Error("New logical elements must start empty, or allowExistingContents must be true");return r in e||(e[r]=[]),e}function u(e,t,n){var a=e;if(e instanceof Comment&&(c(a)&&c(a).length>0))throw new Error("Not implemented: inserting non-empty logical container");if(s(a))throw new Error("Not implemented: moving existing logical children");var i=c(t);if(n<i.length){var u=i[n];u.parentNode.insertBefore(e,u),i.splice(n,0,a)}else d(e,t),i.push(a);a[o]=t,r in a||(a[r]=[])}function s(e){return e[o]||null}function c(e){return e[r]}function l(e){if(e instanceof Element)return e;if(e instanceof Comment)return e.parentNode;throw new Error("Not a valid logical element")}function f(e){var t=c(s(e));return t[Array.prototype.indexOf.call(t,e)+1]||null}function d(e,t){if(t instanceof Element)t.appendChild(e);else{if(!(t instanceof Comment))throw new Error("Cannot append node because the parent is not a valid logical element. Parent: "+t);var n=f(t);n?n.parentNode.insertBefore(e,n):d(e,s(t))}}function p(e){return"function"==typeof Symbol?Symbol():e}t.toLogicalRootCommentElement=function(e,t){if(!e.parentNode)throw new Error("Comment not connected to the DOM "+e.textContent);var n=e.parentNode,r=i(n,!0),u=c(r);return Array.from(n.childNodes).forEach((function(e){return u.push(e)})),e[o]=r,t&&(e[a]=t,i(t)),i(e)},t.toLogicalElement=i,t.createAndInsertLogicalContainer=function(e,t){var n=document.createComment("!");return u(n,e,t),n},t.insertLogicalChild=u,t.removeLogicalChild=function e(t,n){var r=c(t).splice(n,1)[0];if(r instanceof Comment)for(var o=c(r);o.length>0;)e(r,0);var a=r;a.parentNode.removeChild(a)},t.getLogicalParent=s,t.getLogicalSiblingEnd=function(e){return e[a]||null},t.getLogicalChild=function(e,t){return c(e)[t]},t.isSvgElement=function(e){return"http://www.w3.org/2000/svg"===l(e).namespaceURI},t.getLogicalChildrenArray=c,t.permuteLogicalChildren=function(e,t){var n=c(e);t.forEach((function(e){e.moveRangeStart=n[e.fromSiblingIndex],e.moveRangeEnd=function e(t){if(t instanceof Element)return t;var n=f(t);if(n)return n.previousSibling;var r=s(t);return r instanceof Element?r.lastChild:e(r)}(e.moveRangeStart)})),t.forEach((function(t){var r=t.moveToBeforeMarker=document.createComment("marker"),o=n[t.toSiblingIndex+1];o?o.parentNode.insertBefore(r,o):d(r,e)})),t.forEach((function(e){for(var t=e.moveToBeforeMarker,n=t.parentNode,r=e.moveRangeStart,o=e.moveRangeEnd,a=r;a;){var i=a.nextSibling;if(n.insertBefore(a,t),a===o)break;a=i}n.removeChild(t)})),t.forEach((function(e){n[e.toSiblingIndex]=e.moveRangeStart}))},t.getClosestDomElement=l},,,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.setPlatform=function(e){return t.platform=e,t.platform}},function(e,t,n){"use strict";var r;Object.defineProperty(t,"__esModule",{value:!0}),t.dispatchEvent=function(e,t){if(!r)throw new Error("eventDispatcher not initialized. Call 'setEventDispatcher' to configure it.");return r(e,t)},t.setEventDispatcher=function(e){r=e}},,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(7),o=n(4);window.Blazor={navigateTo:r.navigateTo,_internal:{attachRootComponentToElement:o.attachRootComponentToElement,navigationManager:r.internalFunctions}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(25),o=n(26),a=n(12),i=n(29),u=n(18),s=n(7),c=document.createElement("template"),l=document.createElementNS("http://www.w3.org/2000/svg","g"),f={submit:!0},d={},p=function(){function e(e){var t=this;this.childComponentLocations={},this.browserRendererId=e,this.eventDelegator=new o.EventDelegator((function(e,n,r,o){!function(e,t,n,r,o){f[e.type]&&e.preventDefault();var a={browserRendererId:t,eventHandlerId:n,eventArgsType:r.type,eventFieldInfo:o};u.dispatchEvent(a,r.data)}(e,t.browserRendererId,n,r,o)})),s.attachToEventDelegator(this.eventDelegator)}return e.prototype.attachRootComponentToLogicalElement=function(e,t){this.attachComponentToElement(e,t),d[e]=t},e.prototype.updateComponent=function(e,t,n,r){var o=this.childComponentLocations[t];if(!o)throw new Error("No element is currently associated with component "+t);var i=d[t];if(i){var u=a.getLogicalSiblingEnd(i);delete d[t],u?function(e,t){var n=a.getLogicalParent(e);if(!n)throw new Error("Can't clear between nodes. The start node does not have a logical parent.");for(var r=a.getLogicalChildrenArray(n),o=r.indexOf(e)+1,i=r.indexOf(t),u=o;u<=i;u++)a.removeLogicalChild(n,o);e.textContent="!"}(i,u):function(e){var t;for(;t=e.firstChild;)e.removeChild(t)}(i)}var s=a.getClosestDomElement(o).ownerDocument,c=s&&s.activeElement;this.applyEdits(e,t,o,0,n,r),c instanceof HTMLElement&&s&&s.activeElement!==c&&c.focus()},e.prototype.disposeComponent=function(e){delete this.childComponentLocations[e]},e.prototype.disposeEventHandler=function(e){this.eventDelegator.removeListener(e)},e.prototype.attachComponentToElement=function(e,t){this.childComponentLocations[e]=t},e.prototype.applyEdits=function(e,t,n,o,i,u){for(var s,c=0,l=o,f=e.arrayBuilderSegmentReader,d=e.editReader,p=e.frameReader,h=f.values(i),m=f.offset(i),v=m+f.count(i),y=m;y<v;y++){var b=e.diffReader.editsEntry(h,y),g=d.editType(b);switch(g){case r.EditType.prependFrame:var w=d.newTreeIndex(b),E=e.referenceFramesEntry(u,w),_=d.siblingIndex(b);this.insertFrame(e,t,n,l+_,u,E,w);break;case r.EditType.removeFrame:_=d.siblingIndex(b);a.removeLogicalChild(n,l+_);break;case r.EditType.setAttribute:w=d.newTreeIndex(b),E=e.referenceFramesEntry(u,w),_=d.siblingIndex(b);if(!((C=a.getLogicalChild(n,l+_))instanceof Element))throw new Error("Cannot set attribute on non-element child");this.applyAttribute(e,t,C,E);break;case r.EditType.removeAttribute:var C;_=d.siblingIndex(b);if(!((C=a.getLogicalChild(n,l+_))instanceof HTMLElement))throw new Error("Cannot remove attribute from non-element child");var I=d.removedAttributeName(b);this.tryApplySpecialProperty(e,C,I,null)||C.removeAttribute(I);break;case r.EditType.updateText:w=d.newTreeIndex(b),E=e.referenceFramesEntry(u,w),_=d.siblingIndex(b);var S=a.getLogicalChild(n,l+_);if(!(S instanceof Text))throw new Error("Cannot set text content on non-text child");S.textContent=p.textContent(E);break;case r.EditType.updateMarkup:w=d.newTreeIndex(b),E=e.referenceFramesEntry(u,w),_=d.siblingIndex(b);a.removeLogicalChild(n,l+_),this.insertMarkup(e,n,l+_,E);break;case r.EditType.stepIn:_=d.siblingIndex(b);n=a.getLogicalChild(n,l+_),c++,l=0;break;case r.EditType.stepOut:n=a.getLogicalParent(n),l=0===--c?o:0;break;case r.EditType.permutationListEntry:(s=s||[]).push({fromSiblingIndex:l+d.siblingIndex(b),toSiblingIndex:l+d.moveToSiblingIndex(b)});break;case r.EditType.permutationListEnd:a.permuteLogicalChildren(n,s),s=void 0;break;default:throw new Error("Unknown edit type: "+g)}}},e.prototype.insertFrame=function(e,t,n,o,a,u,s){var c=e.frameReader,l=c.frameType(u);switch(l){case r.FrameType.element:return this.insertElement(e,t,n,o,a,u,s),1;case r.FrameType.text:return this.insertText(e,n,o,u),1;case r.FrameType.attribute:throw new Error("Attribute frames should only be present as leading children of element frames.");case r.FrameType.component:return this.insertComponent(e,n,o,u),1;case r.FrameType.region:return this.insertFrameRange(e,t,n,o,a,s+1,s+c.subtreeLength(u));case r.FrameType.elementReferenceCapture:if(n instanceof Element)return i.applyCaptureIdToElement(n,c.elementReferenceCaptureId(u)),0;throw new Error("Reference capture frames can only be children of element frames.");case r.FrameType.markup:return this.insertMarkup(e,n,o,u),1;default:throw new Error("Unknown frame type: "+l)}},e.prototype.insertElement=function(e,t,n,o,i,u,s){var c=e.frameReader,l=c.elementName(u),f="svg"===l||a.isSvgElement(n)?document.createElementNS("http://www.w3.org/2000/svg",l):document.createElement(l),d=a.toLogicalElement(f);a.insertLogicalChild(f,n,o);for(var p=s+c.subtreeLength(u),h=s+1;h<p;h++){var m=e.referenceFramesEntry(i,h);if(c.frameType(m)!==r.FrameType.attribute){this.insertFrameRange(e,t,d,0,i,h,p);break}this.applyAttribute(e,t,f,m)}f instanceof HTMLSelectElement&&"_blazorSelectValue"in f&&v(f,f._blazorSelectValue)},e.prototype.insertComponent=function(e,t,n,r){var o=a.createAndInsertLogicalContainer(t,n),i=e.frameReader.componentId(r);this.attachComponentToElement(i,o)},e.prototype.insertText=function(e,t,n,r){var o=e.frameReader.textContent(r),i=document.createTextNode(o);a.insertLogicalChild(i,t,n)},e.prototype.insertMarkup=function(e,t,n,r){for(var o,i=a.createAndInsertLogicalContainer(t,n),u=e.frameReader.markupContent(r),s=(o=u,a.isSvgElement(t)?(l.innerHTML=o||" ",l):(c.innerHTML=o||" ",c.content)),f=0;s.firstChild;)a.insertLogicalChild(s.firstChild,i,f++)},e.prototype.applyAttribute=function(e,t,n,r){var o=e.frameReader,a=o.attributeName(r),i=o.attributeEventHandlerId(r);if(i){var u=m(a);this.eventDelegator.setListener(n,u,i,t)}else this.tryApplySpecialProperty(e,n,a,r)||n.setAttribute(a,o.attributeValue(r))},e.prototype.tryApplySpecialProperty=function(e,t,n,r){switch(n){case"value":return this.tryApplyValueProperty(e,t,r);case"checked":return this.tryApplyCheckedProperty(e,t,r);default:return!!n.startsWith("__internal_")&&(this.applyInternalAttribute(e,t,n.substring("__internal_".length),r),!0)}},e.prototype.applyInternalAttribute=function(e,t,n,r){var o=r?e.frameReader.attributeValue(r):null;if(n.startsWith("stopPropagation_")){var a=m(n.substring("stopPropagation_".length));this.eventDelegator.setStopPropagation(t,a,null!==o)}else{if(!n.startsWith("preventDefault_"))throw new Error("Unsupported internal attribute '"+n+"'");a=m(n.substring("preventDefault_".length));this.eventDelegator.setPreventDefault(t,a,null!==o)}},e.prototype.tryApplyValueProperty=function(e,t,n){var r=e.frameReader;if("INPUT"===t.tagName&&"time"===t.getAttribute("type")&&!t.getAttribute("step")){var o=n?r.attributeValue(n):null;if(o)return t.value=o.substring(0,5),!0}switch(t.tagName){case"INPUT":case"SELECT":case"TEXTAREA":var a=n?r.attributeValue(n):null;return t instanceof HTMLSelectElement?(v(t,a),t._blazorSelectValue=a):t.value=a,!0;case"OPTION":(a=n?r.attributeValue(n):null)||""===a?t.setAttribute("value",a):t.removeAttribute("value");var i=this.findClosestAncestorSelectElement(t);return i&&"_blazorSelectValue"in i&&i._blazorSelectValue===a&&(this.tryApplyValueProperty(e,i,n),delete i._blazorSelectValue),!0;default:return!1}},e.prototype.tryApplyCheckedProperty=function(e,t,n){if("INPUT"===t.tagName){var r=n?e.frameReader.attributeValue(n):null;return t.checked=null!==r,!0}return!1},e.prototype.findClosestAncestorSelectElement=function(e){for(;e;){if(e instanceof HTMLSelectElement)return e;e=e.parentElement}return null},e.prototype.insertFrameRange=function(e,t,n,r,o,a,i){for(var u=r,s=a;s<i;s++){var c=e.referenceFramesEntry(o,s);r+=this.insertFrame(e,t,n,r,o,c,s),s+=h(e,c)}return r-u},e}();function h(e,t){var n=e.frameReader;switch(n.frameType(t)){case r.FrameType.component:case r.FrameType.element:case r.FrameType.region:return n.subtreeLength(t)-1;default:return 0}}function m(e){if(e.startsWith("on"))return e.substring(2);throw new Error("Attribute should be an event name, but doesn't start with 'on'. Value: '"+e+"'")}function v(e,t){e.value=t||""}t.BrowserRenderer=p},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e){e[e.prependFrame=1]="prependFrame",e[e.removeFrame=2]="removeFrame",e[e.setAttribute=3]="setAttribute",e[e.removeAttribute=4]="removeAttribute",e[e.updateText=5]="updateText",e[e.stepIn=6]="stepIn",e[e.stepOut=7]="stepOut",e[e.updateMarkup=8]="updateMarkup",e[e.permutationListEntry=9]="permutationListEntry",e[e.permutationListEnd=10]="permutationListEnd"}(t.EditType||(t.EditType={})),function(e){e[e.element=1]="element",e[e.text=2]="text",e[e.attribute=3]="attribute",e[e.component=4]="component",e[e.region=5]="region",e[e.elementReferenceCapture=6]="elementReferenceCapture",e[e.markup=8]="markup"}(t.FrameType||(t.FrameType={}))},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(27),o=n(28),a=l(["abort","blur","change","error","focus","load","loadend","loadstart","mouseenter","mouseleave","progress","reset","scroll","submit","unload","DOMNodeInsertedIntoDocument","DOMNodeRemovedFromDocument"]),i=l(["click","dblclick","mousedown","mousemove","mouseup"]),u=function(){function e(t){this.onEvent=t,this.afterClickCallbacks=[];var n=++e.nextEventDelegatorId;this.eventsCollectionKey="_blazorEvents_"+n,this.eventInfoStore=new s(this.onGlobalEvent.bind(this))}return e.prototype.setListener=function(e,t,n,r){var o=this.getEventHandlerInfosForElement(e,!0),a=o.getHandler(t);if(a)this.eventInfoStore.update(a.eventHandlerId,n);else{var i={element:e,eventName:t,eventHandlerId:n,renderingComponentId:r};this.eventInfoStore.add(i),o.setHandler(t,i)}},e.prototype.removeListener=function(e){var t=this.eventInfoStore.remove(e);if(t){var n=t.element,r=this.getEventHandlerInfosForElement(n,!1);r&&r.removeHandler(t.eventName)}},e.prototype.notifyAfterClick=function(e){this.afterClickCallbacks.push(e),this.eventInfoStore.addGlobalListener("click")},e.prototype.setStopPropagation=function(e,t,n){this.getEventHandlerInfosForElement(e,!0).stopPropagation(t,n)},e.prototype.setPreventDefault=function(e,t,n){this.getEventHandlerInfosForElement(e,!0).preventDefault(t,n)},e.prototype.onGlobalEvent=function(e){if(e.target instanceof Element){for(var t,n,u=e.target,s=null,c=a.hasOwnProperty(e.type),l=!1;u;){var f=this.getEventHandlerInfosForElement(u,!1);if(f){var d=f.getHandler(e.type);if(d&&(t=u,n=e.type,!((t instanceof HTMLButtonElement||t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement||t instanceof HTMLSelectElement)&&i.hasOwnProperty(n)&&t.disabled))){s||(s=r.EventForDotNet.fromDOMEvent(e));var p=o.EventFieldInfo.fromEvent(d.renderingComponentId,e);this.onEvent(e,d.eventHandlerId,s,p)}f.stopPropagation(e.type)&&(l=!0),f.preventDefault(e.type)&&e.preventDefault()}u=c||l?null:u.parentElement}"click"===e.type&&this.afterClickCallbacks.forEach((function(t){return t(e)}))}},e.prototype.getEventHandlerInfosForElement=function(e,t){return e.hasOwnProperty(this.eventsCollectionKey)?e[this.eventsCollectionKey]:t?e[this.eventsCollectionKey]=new c:null},e.nextEventDelegatorId=0,e}();t.EventDelegator=u;var s=function(){function e(e){this.globalListener=e,this.infosByEventHandlerId={},this.countByEventName={}}return e.prototype.add=function(e){if(this.infosByEventHandlerId[e.eventHandlerId])throw new Error("Event "+e.eventHandlerId+" is already tracked");this.infosByEventHandlerId[e.eventHandlerId]=e,this.addGlobalListener(e.eventName)},e.prototype.addGlobalListener=function(e){if(this.countByEventName.hasOwnProperty(e))this.countByEventName[e]++;else{this.countByEventName[e]=1;var t=a.hasOwnProperty(e);document.addEventListener(e,this.globalListener,t)}},e.prototype.update=function(e,t){if(this.infosByEventHandlerId.hasOwnProperty(t))throw new Error("Event "+t+" is already tracked");var n=this.infosByEventHandlerId[e];delete this.infosByEventHandlerId[e],n.eventHandlerId=t,this.infosByEventHandlerId[t]=n},e.prototype.remove=function(e){var t=this.infosByEventHandlerId[e];if(t){delete this.infosByEventHandlerId[e];var n=t.eventName;0==--this.countByEventName[n]&&(delete this.countByEventName[n],document.removeEventListener(n,this.globalListener))}return t},e}(),c=function(){function e(){this.handlers={},this.preventDefaultFlags=null,this.stopPropagationFlags=null}return e.prototype.getHandler=function(e){return this.handlers.hasOwnProperty(e)?this.handlers[e]:null},e.prototype.setHandler=function(e,t){this.handlers[e]=t},e.prototype.removeHandler=function(e){delete this.handlers[e]},e.prototype.preventDefault=function(e,t){return void 0!==t&&(this.preventDefaultFlags=this.preventDefaultFlags||{},this.preventDefaultFlags[e]=t),!!this.preventDefaultFlags&&this.preventDefaultFlags[e]},e.prototype.stopPropagation=function(e,t){return void 0!==t&&(this.stopPropagationFlags=this.stopPropagationFlags||{},this.stopPropagationFlags[e]=t),!!this.stopPropagationFlags&&this.stopPropagationFlags[e]},e}();function l(e){var t={};return e.forEach((function(e){t[e]=!0})),t}},function(e,t,n){"use strict";var r=this&&this.__assign||function(){return(r=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var o in t=arguments[n])Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o]);return e}).apply(this,arguments)};Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){this.type=e,this.data=t}return e.fromDOMEvent=function(t){var n=t.target;switch(t.type){case"input":case"change":if(function(e){return-1!==i.indexOf(e.getAttribute("type"))}(n)){var o=function(e){var t=e.value,n=e.type;switch(n){case"date":case"datetime-local":case"month":return t;case"time":return 5===t.length?t+":00":t;case"week":return t}throw new Error("Invalid element type '"+n+"'.")}(n);return new e("change",{type:t.type,value:o})}var u=function(e){return!!e&&"INPUT"===e.tagName&&"checkbox"===e.getAttribute("type")}(n)?!!n.checked:n.value;return new e("change",{type:t.type,value:u});case"copy":case"cut":case"paste":return new e("clipboard",{type:t.type});case"drag":case"dragend":case"dragenter":case"dragleave":case"dragover":case"dragstart":case"drop":return new e("drag",function(e){return r(r({},a(e)),{dataTransfer:e.dataTransfer})}(t));case"focus":case"blur":case"focusin":case"focusout":return new e("focus",{type:t.type});case"keydown":case"keyup":case"keypress":return new e("keyboard",function(e){return{type:e.type,key:e.key,code:e.code,location:e.location,repeat:e.repeat,ctrlKey:e.ctrlKey,shiftKey:e.shiftKey,altKey:e.altKey,metaKey:e.metaKey}}(t));case"contextmenu":case"click":case"mouseover":case"mouseout":case"mousemove":case"mousedown":case"mouseup":case"dblclick":return new e("mouse",a(t));case"error":return new e("error",function(e){return{type:e.type,message:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno}}(t));case"loadstart":case"timeout":case"abort":case"load":case"loadend":case"progress":return new e("progress",function(e){return{type:e.type,lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total}}(t));case"touchcancel":case"touchend":case"touchmove":case"touchenter":case"touchleave":case"touchstart":return new e("touch",function(e){function t(e){for(var t=[],n=0;n<e.length;n++){var r=e[n];t.push({identifier:r.identifier,clientX:r.clientX,clientY:r.clientY,screenX:r.screenX,screenY:r.screenY,pageX:r.pageX,pageY:r.pageY})}return t}return{type:e.type,detail:e.detail,touches:t(e.touches),targetTouches:t(e.targetTouches),changedTouches:t(e.changedTouches),ctrlKey:e.ctrlKey,shiftKey:e.shiftKey,altKey:e.altKey,metaKey:e.metaKey}}(t));case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointerenter":case"pointerleave":case"pointermove":case"pointerout":case"pointerover":case"pointerup":return new e("pointer",function(e){return r(r({},a(e)),{pointerId:e.pointerId,width:e.width,height:e.height,pressure:e.pressure,tiltX:e.tiltX,tiltY:e.tiltY,pointerType:e.pointerType,isPrimary:e.isPrimary})}(t));case"wheel":case"mousewheel":return new e("wheel",function(e){return r(r({},a(e)),{deltaX:e.deltaX,deltaY:e.deltaY,deltaZ:e.deltaZ,deltaMode:e.deltaMode})}(t));default:return new e("unknown",{type:t.type})}},e}();function a(e){return{type:e.type,detail:e.detail,screenX:e.screenX,screenY:e.screenY,clientX:e.clientX,clientY:e.clientY,offsetX:e.offsetX,offsetY:e.offsetY,button:e.button,buttons:e.buttons,ctrlKey:e.ctrlKey,shiftKey:e.shiftKey,altKey:e.altKey,metaKey:e.metaKey}}t.EventForDotNet=o;var i=["date","datetime-local","month","time","week"]},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){this.componentId=e,this.fieldValue=t}return e.fromEvent=function(t,n){var r=n.target;if(r instanceof Element){var o=function(e){if(e instanceof HTMLInputElement)return e.type&&"checkbox"===e.type.toLowerCase()?{value:e.checked}:{value:e.value};if(e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement)return{value:e.value};return null}(r);if(o)return new e(t,o.value)}return null},e}();t.EventFieldInfo=r},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(3);function o(e){return"_bl_"+e}t.applyCaptureIdToElement=function(e,t){e.setAttribute(o(t),"")};r.DotNet.attachReviver((function(e,t){return t&&"object"==typeof t&&t.hasOwnProperty("__internalId")&&"string"==typeof t.__internalId?(n=t.__internalId,r="["+o(n)+"]",document.querySelector(r)):t;var n,r}))},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}};Object.defineProperty(t,"__esModule",{value:!0});var a=!1;t.showErrorNotification=function(){return r(this,void 0,void 0,(function(){var e;return o(this,(function(t){return(e=document.querySelector("#blazor-error-ui"))&&(e.style.display="block"),a||(a=!0,document.querySelectorAll("#blazor-error-ui .reload").forEach((function(e){e.onclick=function(e){location.reload(),e.preventDefault()}})),document.querySelectorAll("#blazor-error-ui .dismiss").forEach((function(e){e.onclick=function(e){var t=document.querySelector("#blazor-error-ui");t&&(t.style.display="none"),e.preventDefault()}}))),[2]}))}))}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=Math.pow(2,32),o=Math.pow(2,21)-1;function a(e,t){return e[t]+(e[t+1]<<8)+(e[t+2]<<16)+(e[t+3]<<24>>>0)}t.readInt32LE=function(e,t){return e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24},t.readUint32LE=a,t.readUint64LE=function(e,t){var n=a(e,t+4);if(n>o)throw new Error("Cannot read uint64 with high order part "+n+", because the result would exceed Number.MAX_SAFE_INTEGER.");return n*r+a(e,t)},t.readLEB128=function(e,t){for(var n=0,r=0,o=0;o<4;o++){var a=e[t+o];if(n|=(127&a)<<r,a<128)break;r+=7}return n},t.numLEB128Bytes=function(e){return e<128?1:e<16384?2:e<2097152?3:4}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r="function"==typeof TextDecoder?new TextDecoder("utf-8"):null;t.decodeUtf8=r?r.decode.bind(r):function(e){var t=0,n=e.length,r=[],o=[];for(;t<n;){var a=e[t++];if(0===a)break;if(0==(128&a))r.push(a);else if(192==(224&a)){var i=63&e[t++];r.push((31&a)<<6|i)}else if(224==(240&a)){i=63&e[t++];var u=63&e[t++];r.push((31&a)<<12|i<<6|u)}else if(240==(248&a)){i=63&e[t++],u=63&e[t++];var s=63&e[t++],c=(7&a)<<18|i<<12|u<<6|s;c>65535&&(c-=65536,r.push(c>>>10&1023|55296),c=56320|1023&c),r.push(c)}r.length>1024&&(o.push(String.fromCharCode.apply(null,r)),r.length=0)}return o.push(String.fromCharCode.apply(null,r)),o.join("")}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.shouldAutoStart=function(){return!(!document||!document.currentScript||"false"===document.currentScript.getAttribute("autostart"))}},,,,,,,,,,function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}},a=this&&this.__read||function(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,o,a=n.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(r=a.next()).done;)i.push(r.value)}catch(e){o={error:e}}finally{try{r&&!r.done&&(n=a.return)&&n.call(a)}finally{if(o)throw o.error}}return i};Object.defineProperty(t,"__esModule",{value:!0});var i=n(3);n(22);var u=n(17),s=n(44),c=n(4),l=n(47),f=n(33),d=n(18),p=n(48),h=n(49),m=n(50),v=!1;function y(e){return r(this,void 0,void 0,(function(){var t,n,f,y,b,g,w,E=this;return o(this,(function(_){switch(_.label){case 0:if(v)throw new Error("Blazor has already started.");return v=!0,d.setEventDispatcher((function(e,t){return i.DotNet.invokeMethodAsync("Microsoft.AspNetCore.Components.WebAssembly","DispatchEvent",e,JSON.stringify(t))})),t=u.setPlatform(s.monoPlatform),window.Blazor.platform=t,window.Blazor._internal.renderBatch=function(e,t){c.renderBatch(e,new l.SharedMemoryRenderBatch(t))},n=window.Blazor._internal.navigationManager.getBaseURI,f=window.Blazor._internal.navigationManager.getLocationHref,window.Blazor._internal.navigationManager.getUnmarshalledBaseURI=function(){return BINDING.js_string_to_mono_string(n())},window.Blazor._internal.navigationManager.getUnmarshalledLocationHref=function(){return BINDING.js_string_to_mono_string(f())},window.Blazor._internal.navigationManager.listenForNavigationEvents((function(e,t){return r(E,void 0,void 0,(function(){return o(this,(function(n){switch(n.label){case 0:return[4,i.DotNet.invokeMethodAsync("Microsoft.AspNetCore.Components.WebAssembly","NotifyLocationChanged",e,t)];case 1:return n.sent(),[2]}}))}))})),[4,m.BootConfigResult.initAsync()];case 1:return y=_.sent(),[4,Promise.all([p.WebAssemblyResourceLoader.initAsync(y.bootConfig,e||{}),h.WebAssemblyConfigLoader.initAsync(y)])];case 2:b=a.apply(void 0,[_.sent(),1]),g=b[0],_.label=3;case 3:return _.trys.push([3,5,,6]),[4,t.start(g)];case 4:return _.sent(),[3,6];case 5:throw w=_.sent(),new Error("Failed to start platform. Reason: "+w);case 6:return t.callEntryPoint(g.bootConfig.entryAssembly),[2]}}))}))}window.Blazor.start=y,f.shouldAutoStart()&&y().catch((function(e){"undefined"!=typeof Module&&Module.printErr?Module.printErr(e):console.error(e)}))},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}};Object.defineProperty(t,"__esModule",{value:!0});var a,i=n(3),u=n(45),s=n(30),c=n(46),l=Math.pow(2,32),f=Math.pow(2,21)-1;function d(e){return Module.HEAP32[e>>2]}t.monoPlatform={start:function(e){return new Promise((function(t,n){var l,f;u.attachDebuggerHotkey(e),window.Browser={init:function(){}},l=function(){window.Module=function(e,t,n){var l=this,f=e.bootConfig.resources,d=window.Module||{},h=["DEBUGGING ENABLED"];d.print=function(e){return h.indexOf(e)<0&&console.log(e)},d.printErr=function(e){console.error(e),s.showErrorNotification()},d.preRun=d.preRun||[],d.postRun=d.postRun||[],d.preloadPlugins=[];var y,b=e.loadResources(f.assembly,(function(e){return"_framework/_bin/"+e}),"assembly"),g=e.loadResources(f.pdb||{},(function(e){return"_framework/_bin/"+e}),"pdb"),w=e.loadResource("dotnet.wasm","_framework/wasm/dotnet.wasm",e.bootConfig.resources.runtime["dotnet.wasm"],"dotnetwasm");return e.bootConfig.resources.runtime.hasOwnProperty("dotnet.timezones.dat")&&(y=e.loadResource("dotnet.timezones.dat","_framework/wasm/dotnet.timezones.dat",e.bootConfig.resources.runtime["dotnet.timezones.dat"],"timezonedata")),d.instantiateWasm=function(e,t){return r(l,void 0,void 0,(function(){var n,r;return o(this,(function(o){switch(o.label){case 0:return o.trys.push([0,3,,4]),[4,w];case 1:return[4,v(o.sent(),e)];case 2:return n=o.sent(),[3,4];case 3:throw r=o.sent(),d.printErr(r),r;case 4:return t(n),[2]}}))})),[]},d.preRun.push((function(){a=cwrap("mono_wasm_add_assembly",null,["string","number","number"]),cwrap("mono_wasm_string_get_utf8","number",["number"]),MONO.loaded_files=[],y&&function(e){r(this,void 0,void 0,(function(){var t,n;return o(this,(function(r){switch(r.label){case 0:return t="blazor:timezonedata",addRunDependency(t),[4,e.response];case 1:return[4,r.sent().arrayBuffer()];case 2:return n=r.sent(),c.loadTimezoneData(n),removeRunDependency(t),[2]}}))}))}(y),b.forEach((function(e){return E(e,function(e,t){var n=e.lastIndexOf(".");if(n<0)throw new Error("No extension to replace in '"+e+"'");return e.substr(0,n)+t}(e.name,".dll"))})),g.forEach((function(e){return E(e,e.name)})),window.Blazor._internal.dotNetCriticalError=function(e){d.printErr(BINDING.conv_string(e)||"(null)")},window.Blazor._internal.getSatelliteAssemblies=function(t){var n=BINDING.mono_array_to_js_array(t),a=e.bootConfig.resources.satelliteResources;if(a){var i=Promise.all(n.filter((function(e){return a.hasOwnProperty(e)})).map((function(t){return e.loadResources(a[t],(function(e){return"_framework/_bin/"+e}),"assembly")})).reduce((function(e,t){return e.concat(t)}),new Array).map((function(e){return r(l,void 0,void 0,(function(){return o(this,(function(t){switch(t.label){case 0:return[4,e.response];case 1:return[2,t.sent().arrayBuffer()]}}))}))})));return BINDING.js_to_mono_obj(i.then((function(e){return e.length&&(window.Blazor._internal.readSatelliteAssemblies=function(){for(var t=BINDING.mono_obj_array_new(e.length),n=0;n<e.length;n++)BINDING.mono_obj_array_set(t,n,BINDING.js_typed_array_to_array(new Uint8Array(e[n])));return t}),e.length})))}return BINDING.js_to_mono_obj(Promise.resolve(0))}})),d.postRun.push((function(){var n,r,o;e.bootConfig.debugBuild&&e.bootConfig.cacheBootResources&&e.logToConsole(),e.purgeUnusedCacheEntriesAsync(),MONO.mono_wasm_setenv("MONO_URI_DOTNETRELATIVEORABSOLUTE","true"),cwrap("mono_wasm_load_runtime",null,["string","number"])("appBinDir",u.hasDebuggingEnabled()?-1:0),MONO.mono_wasm_runtime_ready(),n=m("Microsoft.AspNetCore.Components.WebAssembly","Microsoft.AspNetCore.Components.WebAssembly.Services.DefaultWebAssemblyJSRuntime","InvokeDotNet"),r=m("Microsoft.AspNetCore.Components.WebAssembly","Microsoft.AspNetCore.Components.WebAssembly.Services.DefaultWebAssemblyJSRuntime","BeginInvokeDotNet"),o=m("Microsoft.AspNetCore.Components.WebAssembly","Microsoft.AspNetCore.Components.WebAssembly.Services.DefaultWebAssemblyJSRuntime","EndInvokeJS"),i.DotNet.attachDispatcher({beginInvokeDotNetFromJS:function(e,t,n,o,a){if(!o&&!t)throw new Error("Either assemblyName or dotNetObjectId must have a non null value.");var i=o?o.toString():t;r(e?e.toString():null,i,n,a)},endInvokeJSFromDotNet:function(e,t,n){o(n)},invokeDotNetFromJS:function(e,t,r,o){return n(e||null,t,r?r.toString():null,o)}}),t()})),d;function E(e,t){return r(this,void 0,void 0,(function(){var r,i,u,s,c;return o(this,(function(o){switch(o.label){case 0:r="blazor:"+e.name,addRunDependency(r),o.label=1;case 1:return o.trys.push([1,3,,4]),[4,e.response.then((function(e){return e.arrayBuffer()}))];case 2:return i=o.sent(),u=new Uint8Array(i),s=Module._malloc(u.length),new Uint8Array(Module.HEAPU8.buffer,s,u.length).set(u),a(t,s,u.length),MONO.loaded_files.push((l=e.url,p.href=l,p.href)),[3,4];case 3:return c=o.sent(),n(c),[2];case 4:return removeRunDependency(r),[2]}var l}))}))}}(e,t,n),function(e){if("undefined"==typeof WebAssembly||!WebAssembly.validate)throw new Error("This browser does not support WebAssembly.");var t=Object.keys(e.bootConfig.resources.runtime).filter((function(e){return e.startsWith("dotnet.")&&e.endsWith(".js")}))[0],n=e.bootConfig.resources.runtime[t],r=document.createElement("script");if(r.src="_framework/wasm/"+t,r.defer=!0,e.bootConfig.cacheBootResources&&(r.integrity=n,r.crossOrigin="anonymous"),e.startOptions.loadBootResource){var o=e.startOptions.loadBootResource("dotnetjs",t,r.src,n);if("string"==typeof o)r.src=o;else if(o)throw new Error("For a dotnetjs resource, custom loaders must supply a URI string.")}document.body.appendChild(r)}(e)},f=document.createElement("script"),window.__wasmmodulecallback__=l,f.type="text/javascript",f.text="var Module; window.__wasmmodulecallback__(); delete window.__wasmmodulecallback__;",document.body.appendChild(f)}))},callEntryPoint:function(e){m("Microsoft.AspNetCore.Components.WebAssembly","Microsoft.AspNetCore.Components.WebAssembly.Hosting.EntrypointInvoker","InvokeEntrypoint")(e,null)},toUint8Array:function(e){var t=h(e),n=d(t);return new Uint8Array(Module.HEAPU8.buffer,t+4,n)},getArrayLength:function(e){return d(h(e))},getArrayEntryPtr:function(e,t,n){return h(e)+4+t*n},getObjectFieldsBaseAddress:function(e){return e+8},readInt16Field:function(e,t){return n=e+(t||0),Module.HEAP16[n>>1];var n},readInt32Field:function(e,t){return d(e+(t||0))},readUint64Field:function(e,t){return function(e){var t=e>>2,n=Module.HEAPU32[t+1];if(n>f)throw new Error("Cannot read uint64 with high order part "+n+", because the result would exceed Number.MAX_SAFE_INTEGER.");return n*l+Module.HEAPU32[t]}(e+(t||0))},readFloatField:function(e,t){return n=e+(t||0),Module.HEAPF32[n>>2];var n},readObjectField:function(e,t){return d(e+(t||0))},readStringField:function(e,t,n){var r=d(e+(t||0));if(0===r)return null;if(n){var o=BINDING.unbox_mono_obj(r);return"boolean"==typeof o?o?"":null:o}return BINDING.conv_string(r)},readStructField:function(e,t){return e+(t||0)}};var p=document.createElement("a");function h(e){return e+12}function m(e,t,n){var r="["+e+"] "+t+":"+n;return BINDING.bind_static_method(r)}function v(e,t){return r(this,void 0,void 0,(function(){var n,r;return o(this,(function(o){switch(o.label){case 0:if("function"!=typeof WebAssembly.instantiateStreaming)return[3,4];o.label=1;case 1:return o.trys.push([1,3,,4]),[4,WebAssembly.instantiateStreaming(e.response,t)];case 2:return[2,o.sent().instance];case 3:return n=o.sent(),console.info("Streaming compilation failed. Falling back to ArrayBuffer instantiation. ",n),[3,4];case 4:return[4,e.response.then((function(e){return e.arrayBuffer()}))];case 5:return r=o.sent(),[4,WebAssembly.instantiate(r,t)];case 6:return[2,o.sent().instance]}}))}))}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=window.chrome&&navigator.userAgent.indexOf("Edge")<0,o=!1;function a(){return o&&r}t.hasDebuggingEnabled=a,t.attachDebuggerHotkey=function(e){o=!!e.bootConfig.resources.pdb;var t=navigator.platform.match(/^Mac/i)?"Cmd":"Alt";a()&&console.info("Debugging hotkey: Shift+"+t+"+D (when application has focus)"),document.addEventListener("keydown",(function(e){var t;e.shiftKey&&(e.metaKey||e.altKey)&&"KeyD"===e.code&&(o?r?((t=document.createElement("a")).href="_framework/debug?url="+encodeURIComponent(location.href),t.target="_blank",t.rel="noopener noreferrer",t.click()):console.error("Currently, only Microsoft Edge (80+), or Google Chrome, are supported for debugging."):console.error("Cannot start debugging, because the application was not compiled with debugging enabled."))}))}},function(e,t,n){"use strict";var r=this&&this.__values||function(e){var t="function"==typeof Symbol&&Symbol.iterator,n=t&&e[t],r=0;if(n)return n.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},o=this&&this.__read||function(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,o,a=n.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(r=a.next()).done;)i.push(r.value)}catch(e){o={error:e}}finally{try{r&&!r.done&&(n=a.return)&&n.call(a)}finally{if(o)throw o.error}}return i};Object.defineProperty(t,"__esModule",{value:!0});var a=n(31),i=n(32);t.loadTimezoneData=function(e){var t,n,u=new Uint8Array(e),s=a.readInt32LE(u,0);u=u.slice(4);var c=i.decodeUtf8(u.slice(0,s)),l=JSON.parse(c);u=u.slice(s),Module.FS_createPath("/","zoneinfo",!0,!0),new Set(l.map((function(e){return e[0].split("/")[0]}))).forEach((function(e){return Module.FS_createPath("/zoneinfo",e,!0,!0)}));try{for(var f=r(l),d=f.next();!d.done;d=f.next()){var p=o(d.value,2),h=p[0],m=p[1],v=u.slice(0,m);Module.FS_createDataFile("/zoneinfo/"+h,null,v,!0,!0,!0),u=u.slice(m)}}catch(e){t={error:e}}finally{try{d&&!d.done&&(n=f.return)&&n.call(f)}finally{if(t)throw t.error}}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(17),o=function(){function e(e){this.batchAddress=e,this.arrayRangeReader=a,this.arrayBuilderSegmentReader=i,this.diffReader=u,this.editReader=s,this.frameReader=c}return e.prototype.updatedComponents=function(){return r.platform.readStructField(this.batchAddress,0)},e.prototype.referenceFrames=function(){return r.platform.readStructField(this.batchAddress,a.structLength)},e.prototype.disposedComponentIds=function(){return r.platform.readStructField(this.batchAddress,2*a.structLength)},e.prototype.disposedEventHandlerIds=function(){return r.platform.readStructField(this.batchAddress,3*a.structLength)},e.prototype.updatedComponentsEntry=function(e,t){return l(e,t,u.structLength)},e.prototype.referenceFramesEntry=function(e,t){return l(e,t,c.structLength)},e.prototype.disposedComponentIdsEntry=function(e,t){var n=l(e,t,4);return r.platform.readInt32Field(n)},e.prototype.disposedEventHandlerIdsEntry=function(e,t){var n=l(e,t,8);return r.platform.readUint64Field(n)},e}();t.SharedMemoryRenderBatch=o;var a={structLength:8,values:function(e){return r.platform.readObjectField(e,0)},count:function(e){return r.platform.readInt32Field(e,4)}},i={structLength:12,values:function(e){var t=r.platform.readObjectField(e,0),n=r.platform.getObjectFieldsBaseAddress(t);return r.platform.readObjectField(n,0)},offset:function(e){return r.platform.readInt32Field(e,4)},count:function(e){return r.platform.readInt32Field(e,8)}},u={structLength:4+i.structLength,componentId:function(e){return r.platform.readInt32Field(e,0)},edits:function(e){return r.platform.readStructField(e,4)},editsEntry:function(e,t){return l(e,t,s.structLength)}},s={structLength:20,editType:function(e){return r.platform.readInt32Field(e,0)},siblingIndex:function(e){return r.platform.readInt32Field(e,4)},newTreeIndex:function(e){return r.platform.readInt32Field(e,8)},moveToSiblingIndex:function(e){return r.platform.readInt32Field(e,8)},removedAttributeName:function(e){return r.platform.readStringField(e,16)}},c={structLength:36,frameType:function(e){return r.platform.readInt16Field(e,4)},subtreeLength:function(e){return r.platform.readInt32Field(e,8)},elementReferenceCaptureId:function(e){return r.platform.readStringField(e,16)},componentId:function(e){return r.platform.readInt32Field(e,12)},elementName:function(e){return r.platform.readStringField(e,16)},textContent:function(e){return r.platform.readStringField(e,16)},markupContent:function(e){return r.platform.readStringField(e,16)},attributeName:function(e){return r.platform.readStringField(e,16)},attributeValue:function(e){return r.platform.readStringField(e,24,!0)},attributeEventHandlerId:function(e){return r.platform.readUint64Field(e,8)}};function l(e,t,n){return r.platform.getArrayEntryPtr(e,t,n)}},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}};Object.defineProperty(t,"__esModule",{value:!0});var a=n(7),i=function(){function e(e,t,n){this.bootConfig=e,this.cacheIfUsed=t,this.startOptions=n,this.usedCacheKeys={},this.networkLoads={},this.cacheLoads={}}return e.initAsync=function(t,n){return r(this,void 0,void 0,(function(){var r;return o(this,(function(o){switch(o.label){case 0:return[4,u(t)];case 1:return r=o.sent(),[2,new e(t,r,n)]}}))}))},e.prototype.loadResources=function(e,t,n){var r=this;return Object.keys(e).map((function(o){return r.loadResource(o,t(o),e[o],n)}))},e.prototype.loadResource=function(e,t,n,r){return{name:e,url:t,response:this.cacheIfUsed?this.loadResourceWithCaching(this.cacheIfUsed,e,t,n,r):this.loadResourceWithoutCaching(e,t,n,r)}},e.prototype.logToConsole=function(){var e=Object.values(this.cacheLoads),t=Object.values(this.networkLoads),n=s(e),r=s(t),o=n+r;if(0!==o){var a=this.bootConfig.linkerEnabled?"%c":"\n%cThis application was built with linking (tree shaking) disabled. Published applications will be significantly smaller.";console.groupCollapsed("%cblazor%c Loaded "+c(o)+" resources"+a,"background: purple; color: white; padding: 1px 3px; border-radius: 3px;","font-weight: bold;","font-weight: normal;"),e.length&&(console.groupCollapsed("Loaded "+c(n)+" resources from cache"),console.table(this.cacheLoads),console.groupEnd()),t.length&&(console.groupCollapsed("Loaded "+c(r)+" resources from network"),console.table(this.networkLoads),console.groupEnd()),console.groupEnd()}},e.prototype.purgeUnusedCacheEntriesAsync=function(){return r(this,void 0,void 0,(function(){var e,t,n,a=this;return o(this,(function(i){switch(i.label){case 0:return(e=this.cacheIfUsed)?[4,e.keys()]:[3,3];case 1:return t=i.sent(),n=t.map((function(t){return r(a,void 0,void 0,(function(){return o(this,(function(n){switch(n.label){case 0:return t.url in this.usedCacheKeys?[3,2]:[4,e.delete(t)];case 1:n.sent(),n.label=2;case 2:return[2]}}))}))})),[4,Promise.all(n)];case 2:i.sent(),i.label=3;case 3:return[2]}}))}))},e.prototype.loadResourceWithCaching=function(e,t,n,i,u){return r(this,void 0,void 0,(function(){var r,s,c,l;return o(this,(function(o){switch(o.label){case 0:if(!i||0===i.length)throw new Error("Content hash is required");r=a.toAbsoluteUri(n+"."+i),this.usedCacheKeys[r]=!0,o.label=1;case 1:return o.trys.push([1,3,,4]),[4,e.match(r)];case 2:return s=o.sent(),[3,4];case 3:return o.sent(),[3,4];case 4:return s?(c=parseInt(s.headers.get("content-length")||"0"),this.cacheLoads[t]={responseBytes:c},[2,s]):[3,5];case 5:return[4,this.loadResourceWithoutCaching(t,n,i,u)];case 6:return l=o.sent(),this.addToCacheAsync(e,t,r,l),[2,l]}}))}))},e.prototype.loadResourceWithoutCaching=function(e,t,n,r){if(this.startOptions.loadBootResource){var o=this.startOptions.loadBootResource(r,e,t,n);if(o instanceof Promise)return o;"string"==typeof o&&(t=o)}return fetch(t,{cache:"no-cache",integrity:this.bootConfig.cacheBootResources?n:void 0})},e.prototype.addToCacheAsync=function(e,t,n,a){return r(this,void 0,void 0,(function(){var r,i,u,s;return o(this,(function(o){switch(o.label){case 0:return[4,a.clone().arrayBuffer()];case 1:r=o.sent(),i=function(e){if("undefined"!=typeof performance)return performance.getEntriesByName(e)[0]}(a.url),u=i&&i.encodedBodySize||void 0,this.networkLoads[t]={responseBytes:u},s=new Response(r,{headers:{"content-type":a.headers.get("content-type")||"","content-length":(u||a.headers.get("content-length")||"").toString()}}),o.label=2;case 2:return o.trys.push([2,4,,5]),[4,e.put(n,s)];case 3:return o.sent(),[3,5];case 4:return o.sent(),[3,5];case 5:return[2]}}))}))},e}();function u(e){return r(this,void 0,void 0,(function(){var t,n;return o(this,(function(r){switch(r.label){case 0:if(!e.cacheBootResources||"undefined"==typeof caches)return[2,null];t=document.baseURI.substring(document.location.origin.length),n="blazor-resources-"+t,r.label=1;case 1:return r.trys.push([1,3,,4]),[4,caches.open(n)];case 2:return[2,r.sent()||null];case 3:return r.sent(),[2,null];case 4:return[2]}}))}))}function s(e){return e.reduce((function(e,t){return e+(t.responseBytes||0)}),0)}function c(e){return(e/1048576).toFixed(2)+" MB"}t.WebAssemblyResourceLoader=i},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}};Object.defineProperty(t,"__esModule",{value:!0});var a=function(){function e(){}return e.initAsync=function(e){return r(this,void 0,void 0,(function(){function t(e){return r(this,void 0,void 0,(function(){var t,n;return o(this,(function(r){switch(r.label){case 0:return[4,fetch(e,{method:"GET",credentials:"include",cache:"no-cache"})];case 1:return t=r.sent(),n=Uint8Array.bind,[4,t.arrayBuffer()];case 2:return[2,new(n.apply(Uint8Array,[void 0,r.sent()]))]}}))}))}var n,a=this;return o(this,(function(i){switch(i.label){case 0:return window.Blazor._internal.getApplicationEnvironment=function(){return BINDING.js_string_to_mono_string(e.applicationEnvironment)},[4,Promise.all((e.bootConfig.config||[]).filter((function(t){return"appsettings.json"===t||t==="appsettings."+e.applicationEnvironment+".json"})).map((function(e){return r(a,void 0,void 0,(function(){var n;return o(this,(function(r){switch(r.label){case 0:return n={name:e},[4,t(e)];case 1:return[2,(n.content=r.sent(),n)]}}))}))})))];case 1:return n=i.sent(),window.Blazor._internal.getConfig=function(e){var t=BINDING.conv_string(e),r=n.find((function(e){return e.name===t}));return r?BINDING.js_typed_array_to_array(r.content):void 0},[2]}}))}))},e}();t.WebAssemblyConfigLoader=a},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}};Object.defineProperty(t,"__esModule",{value:!0});var a=function(){function e(e,t){this.bootConfig=e,this.applicationEnvironment=t}return e.initAsync=function(){return r(this,void 0,void 0,(function(){var t,n;return o(this,(function(r){switch(r.label){case 0:return[4,fetch("_framework/blazor.boot.json",{method:"GET",credentials:"include",cache:"no-cache"})];case 1:return t=r.sent(),n=t.headers.get("Blazor-Environment")||"Production",[4,t.json()];case 2:return[2,new e(r.sent(),n)]}}))}))},e}();t.BootConfigResult=a}]); \ No newline at end of file
+!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=43)}([,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e){window.DotNet=e;var t=[],n={},r={},o=1,a=null;function i(e){t.push(e)}function u(e,t,n,r){var o=c();if(o.invokeDotNetFromJS){var a=JSON.stringify(r,m),i=o.invokeDotNetFromJS(e,t,n,a);return i?f(i):null}throw new Error("The current dispatcher does not support synchronous calls from JS to .NET. Use invokeMethodAsync instead.")}function s(e,t,r,a){if(e&&r)throw new Error("For instance method calls, assemblyName should be null. Received '"+e+"'.");var i=o++,u=new Promise((function(e,t){n[i]={resolve:e,reject:t}}));try{var s=JSON.stringify(a,m);c().beginInvokeDotNetFromJS(i,e,t,r,s)}catch(e){l(i,!1,e)}return u}function c(){if(null!==a)return a;throw new Error("No .NET call dispatcher has been set.")}function l(e,t,r){if(!n.hasOwnProperty(e))throw new Error("There is no pending async call with ID "+e+".");var o=n[e];delete n[e],t?o.resolve(r):o.reject(r)}function f(e){return e?JSON.parse(e,(function(e,n){return t.reduce((function(t,n){return n(e,t)}),n)})):null}function d(e){return e instanceof Error?e.message+"\n"+e.stack:e?e.toString():"null"}function p(e){if(r.hasOwnProperty(e))return r[e];var t,n=window,o="window";if(e.split(".").forEach((function(e){if(!(e in n))throw new Error("Could not find '"+e+"' in '"+o+"'.");t=n,n=n[e],o+="."+e})),n instanceof Function)return n=n.bind(t),r[e]=n,n;throw new Error("The value '"+o+"' is not a function.")}e.attachDispatcher=function(e){a=e},e.attachReviver=i,e.invokeMethod=function(e,t){for(var n=[],r=2;r<arguments.length;r++)n[r-2]=arguments[r];return u(e,t,null,n)},e.invokeMethodAsync=function(e,t){for(var n=[],r=2;r<arguments.length;r++)n[r-2]=arguments[r];return s(e,t,null,n)},e.jsCallDispatcher={findJSFunction:p,invokeJSFromDotNet:function(e,t){var n=p(e).apply(null,f(t));return null==n?null:JSON.stringify(n,m)},beginInvokeJSFromDotNet:function(e,t,n){var r=new Promise((function(e){e(p(t).apply(null,f(n)))}));e&&r.then((function(t){return c().endInvokeJSFromDotNet(e,!0,JSON.stringify([e,!0,t],m))}),(function(t){return c().endInvokeJSFromDotNet(e,!1,JSON.stringify([e,!1,d(t)]))}))},endInvokeDotNetFromJS:function(e,t,n){var r=t?n:new Error(n);l(parseInt(e),t,r)}};var h=function(){function e(e){this._id=e}return e.prototype.invokeMethod=function(e){for(var t=[],n=1;n<arguments.length;n++)t[n-1]=arguments[n];return u(null,e,this._id,t)},e.prototype.invokeMethodAsync=function(e){for(var t=[],n=1;n<arguments.length;n++)t[n-1]=arguments[n];return s(null,e,this._id,t)},e.prototype.dispose=function(){s(null,"__Dispose",this._id,null).catch((function(e){return console.error(e)}))},e.prototype.serializeAsArg=function(){return{__dotNetObject:this._id}},e}();function m(e,t){return t instanceof h?t.serializeAsArg():t}i((function(e,t){return t&&"object"==typeof t&&t.hasOwnProperty("__dotNetObject")?new h(t.__dotNetObject):t}))}(t.DotNet||(t.DotNet={}))},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(23),n(17);var r=n(24),o=n(12),a={},i=!1;function u(e,t,n){var o=a[e];o||(o=a[e]=new r.BrowserRenderer(e)),o.attachRootComponentToLogicalElement(n,t)}t.attachRootComponentToLogicalElement=u,t.attachRootComponentToElement=function(e,t,n){var r=document.querySelector(e);if(!r)throw new Error("Could not find any element matching selector '"+e+"'.");u(n||0,o.toLogicalElement(r,!0),t)},t.renderBatch=function(e,t){var n=a[e];if(!n)throw new Error("There is no browser renderer with ID "+e+".");for(var r=t.arrayRangeReader,o=t.updatedComponents(),u=r.values(o),s=r.count(o),c=t.referenceFrames(),l=r.values(c),f=t.diffReader,d=0;d<s;d++){var p=t.updatedComponentsEntry(u,d),h=f.componentId(p),m=f.edits(p);n.updateComponent(t,h,m,l)}var v=t.disposedComponentIds(),y=r.values(v),b=r.count(v);for(d=0;d<b;d++){h=t.disposedComponentIdsEntry(y,d);n.disposeComponent(h)}var g=t.disposedEventHandlerIds(),w=r.values(g),E=r.count(g);for(d=0;d<E;d++){var _=t.disposedEventHandlerIdsEntry(w,d);n.disposeEventHandler(_)}i&&(i=!1,window.scrollTo&&window.scrollTo(0,0))},t.resetScrollAfterNextBatch=function(){i=!0}},,,function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}};Object.defineProperty(t,"__esModule",{value:!0}),n(3);var a,i=n(4),u=!1,s=!1,c=null;function l(e,t,n){void 0===n&&(n=!1);var r=p(e);if(!t&&h(r))f(r,!1,n);else if(t&&location.href===e){var o=e+"?";history.replaceState(null,"",o),location.replace(e)}else n?history.replaceState(null,"",r):location.href=e}function f(e,t,n){void 0===n&&(n=!1),i.resetScrollAfterNextBatch(),n?history.replaceState(null,"",e):history.pushState(null,"",e),d(t)}function d(e){return r(this,void 0,void 0,(function(){return o(this,(function(t){switch(t.label){case 0:return c?[4,c(location.href,e)]:[3,2];case 1:t.sent(),t.label=2;case 2:return[2]}}))}))}function p(e){return(a=a||document.createElement("a")).href=e,a.href}function h(e){var t,n=(t=document.baseURI).substr(0,t.lastIndexOf("/")+1);return e.startsWith(n)}t.internalFunctions={listenForNavigationEvents:function(e){if(c=e,s)return;s=!0,window.addEventListener("popstate",(function(){return d(!1)}))},enableNavigationInterception:function(){u=!0},navigateTo:l,getBaseURI:function(){return document.baseURI},getLocationHref:function(){return location.href}},t.attachToEventDelegator=function(e){e.notifyAfterClick((function(e){if(u&&0===e.button&&!function(e){return e.ctrlKey||e.shiftKey||e.altKey||e.metaKey}(e)&&!e.defaultPrevented){var t=function e(t,n){return t?t.tagName===n?t:e(t.parentElement,n):null}(e.target,"A");if(t&&t.hasAttribute("href")){var n=t.getAttribute("target");if(!(!n||"_self"===n))return;var r=p(t.getAttribute("href"));h(r)&&(e.preventDefault(),f(r,!0))}}}))},t.navigateTo=l,t.toAbsoluteUri=p},,,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=p("_blazorLogicalChildren"),o=p("_blazorLogicalParent"),a=p("_blazorLogicalEnd");function i(e,t){if(e.childNodes.length>0&&!t)throw new Error("New logical elements must start empty, or allowExistingContents must be true");return r in e||(e[r]=[]),e}function u(e,t,n){var a=e;if(e instanceof Comment&&(c(a)&&c(a).length>0))throw new Error("Not implemented: inserting non-empty logical container");if(s(a))throw new Error("Not implemented: moving existing logical children");var i=c(t);if(n<i.length){var u=i[n];u.parentNode.insertBefore(e,u),i.splice(n,0,a)}else d(e,t),i.push(a);a[o]=t,r in a||(a[r]=[])}function s(e){return e[o]||null}function c(e){return e[r]}function l(e){if(e instanceof Element)return e;if(e instanceof Comment)return e.parentNode;throw new Error("Not a valid logical element")}function f(e){var t=c(s(e));return t[Array.prototype.indexOf.call(t,e)+1]||null}function d(e,t){if(t instanceof Element)t.appendChild(e);else{if(!(t instanceof Comment))throw new Error("Cannot append node because the parent is not a valid logical element. Parent: "+t);var n=f(t);n?n.parentNode.insertBefore(e,n):d(e,s(t))}}function p(e){return"function"==typeof Symbol?Symbol():e}t.toLogicalRootCommentElement=function(e,t){if(!e.parentNode)throw new Error("Comment not connected to the DOM "+e.textContent);var n=e.parentNode,r=i(n,!0),u=c(r);return Array.from(n.childNodes).forEach((function(e){return u.push(e)})),e[o]=r,t&&(e[a]=t,i(t)),i(e)},t.toLogicalElement=i,t.createAndInsertLogicalContainer=function(e,t){var n=document.createComment("!");return u(n,e,t),n},t.insertLogicalChild=u,t.removeLogicalChild=function e(t,n){var r=c(t).splice(n,1)[0];if(r instanceof Comment)for(var o=c(r);o.length>0;)e(r,0);var a=r;a.parentNode.removeChild(a)},t.getLogicalParent=s,t.getLogicalSiblingEnd=function(e){return e[a]||null},t.getLogicalChild=function(e,t){return c(e)[t]},t.isSvgElement=function(e){return"http://www.w3.org/2000/svg"===l(e).namespaceURI},t.getLogicalChildrenArray=c,t.permuteLogicalChildren=function(e,t){var n=c(e);t.forEach((function(e){e.moveRangeStart=n[e.fromSiblingIndex],e.moveRangeEnd=function e(t){if(t instanceof Element)return t;var n=f(t);if(n)return n.previousSibling;var r=s(t);return r instanceof Element?r.lastChild:e(r)}(e.moveRangeStart)})),t.forEach((function(t){var r=t.moveToBeforeMarker=document.createComment("marker"),o=n[t.toSiblingIndex+1];o?o.parentNode.insertBefore(r,o):d(r,e)})),t.forEach((function(e){for(var t=e.moveToBeforeMarker,n=t.parentNode,r=e.moveRangeStart,o=e.moveRangeEnd,a=r;a;){var i=a.nextSibling;if(n.insertBefore(a,t),a===o)break;a=i}n.removeChild(t)})),t.forEach((function(e){n[e.toSiblingIndex]=e.moveRangeStart}))},t.getClosestDomElement=l},,,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.setPlatform=function(e){return t.platform=e,t.platform}},function(e,t,n){"use strict";var r;Object.defineProperty(t,"__esModule",{value:!0}),t.dispatchEvent=function(e,t){if(!r)throw new Error("eventDispatcher not initialized. Call 'setEventDispatcher' to configure it.");return r(e,t)},t.setEventDispatcher=function(e){r=e}},,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(7),o=n(4);window.Blazor={navigateTo:r.navigateTo,_internal:{attachRootComponentToElement:o.attachRootComponentToElement,navigationManager:r.internalFunctions}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(25),o=n(26),a=n(12),i=n(29),u=n(18),s=n(7),c=document.createElement("template"),l=document.createElementNS("http://www.w3.org/2000/svg","g"),f={submit:!0},d={},p=function(){function e(e){var t=this;this.childComponentLocations={},this.browserRendererId=e,this.eventDelegator=new o.EventDelegator((function(e,n,r,o){!function(e,t,n,r,o){f[e.type]&&e.preventDefault();var a={browserRendererId:t,eventHandlerId:n,eventArgsType:r.type,eventFieldInfo:o};u.dispatchEvent(a,r.data)}(e,t.browserRendererId,n,r,o)})),s.attachToEventDelegator(this.eventDelegator)}return e.prototype.attachRootComponentToLogicalElement=function(e,t){this.attachComponentToElement(e,t),d[e]=t},e.prototype.updateComponent=function(e,t,n,r){var o=this.childComponentLocations[t];if(!o)throw new Error("No element is currently associated with component "+t);var i=d[t];if(i){var u=a.getLogicalSiblingEnd(i);delete d[t],u?function(e,t){var n=a.getLogicalParent(e);if(!n)throw new Error("Can't clear between nodes. The start node does not have a logical parent.");for(var r=a.getLogicalChildrenArray(n),o=r.indexOf(e)+1,i=r.indexOf(t),u=o;u<=i;u++)a.removeLogicalChild(n,o);e.textContent="!"}(i,u):function(e){var t;for(;t=e.firstChild;)e.removeChild(t)}(i)}var s=a.getClosestDomElement(o).ownerDocument,c=s&&s.activeElement;this.applyEdits(e,t,o,0,n,r),c instanceof HTMLElement&&s&&s.activeElement!==c&&c.focus()},e.prototype.disposeComponent=function(e){delete this.childComponentLocations[e]},e.prototype.disposeEventHandler=function(e){this.eventDelegator.removeListener(e)},e.prototype.attachComponentToElement=function(e,t){this.childComponentLocations[e]=t},e.prototype.applyEdits=function(e,t,n,o,i,u){for(var s,c=0,l=o,f=e.arrayBuilderSegmentReader,d=e.editReader,p=e.frameReader,h=f.values(i),m=f.offset(i),v=m+f.count(i),y=m;y<v;y++){var b=e.diffReader.editsEntry(h,y),g=d.editType(b);switch(g){case r.EditType.prependFrame:var w=d.newTreeIndex(b),E=e.referenceFramesEntry(u,w),_=d.siblingIndex(b);this.insertFrame(e,t,n,l+_,u,E,w);break;case r.EditType.removeFrame:_=d.siblingIndex(b);a.removeLogicalChild(n,l+_);break;case r.EditType.setAttribute:w=d.newTreeIndex(b),E=e.referenceFramesEntry(u,w),_=d.siblingIndex(b);if(!((C=a.getLogicalChild(n,l+_))instanceof Element))throw new Error("Cannot set attribute on non-element child");this.applyAttribute(e,t,C,E);break;case r.EditType.removeAttribute:var C;_=d.siblingIndex(b);if(!((C=a.getLogicalChild(n,l+_))instanceof HTMLElement))throw new Error("Cannot remove attribute from non-element child");var I=d.removedAttributeName(b);this.tryApplySpecialProperty(e,C,I,null)||C.removeAttribute(I);break;case r.EditType.updateText:w=d.newTreeIndex(b),E=e.referenceFramesEntry(u,w),_=d.siblingIndex(b);var S=a.getLogicalChild(n,l+_);if(!(S instanceof Text))throw new Error("Cannot set text content on non-text child");S.textContent=p.textContent(E);break;case r.EditType.updateMarkup:w=d.newTreeIndex(b),E=e.referenceFramesEntry(u,w),_=d.siblingIndex(b);a.removeLogicalChild(n,l+_),this.insertMarkup(e,n,l+_,E);break;case r.EditType.stepIn:_=d.siblingIndex(b);n=a.getLogicalChild(n,l+_),c++,l=0;break;case r.EditType.stepOut:n=a.getLogicalParent(n),l=0===--c?o:0;break;case r.EditType.permutationListEntry:(s=s||[]).push({fromSiblingIndex:l+d.siblingIndex(b),toSiblingIndex:l+d.moveToSiblingIndex(b)});break;case r.EditType.permutationListEnd:a.permuteLogicalChildren(n,s),s=void 0;break;default:throw new Error("Unknown edit type: "+g)}}},e.prototype.insertFrame=function(e,t,n,o,a,u,s){var c=e.frameReader,l=c.frameType(u);switch(l){case r.FrameType.element:return this.insertElement(e,t,n,o,a,u,s),1;case r.FrameType.text:return this.insertText(e,n,o,u),1;case r.FrameType.attribute:throw new Error("Attribute frames should only be present as leading children of element frames.");case r.FrameType.component:return this.insertComponent(e,n,o,u),1;case r.FrameType.region:return this.insertFrameRange(e,t,n,o,a,s+1,s+c.subtreeLength(u));case r.FrameType.elementReferenceCapture:if(n instanceof Element)return i.applyCaptureIdToElement(n,c.elementReferenceCaptureId(u)),0;throw new Error("Reference capture frames can only be children of element frames.");case r.FrameType.markup:return this.insertMarkup(e,n,o,u),1;default:throw new Error("Unknown frame type: "+l)}},e.prototype.insertElement=function(e,t,n,o,i,u,s){var c=e.frameReader,l=c.elementName(u),f="svg"===l||a.isSvgElement(n)?document.createElementNS("http://www.w3.org/2000/svg",l):document.createElement(l),d=a.toLogicalElement(f);a.insertLogicalChild(f,n,o);for(var p=s+c.subtreeLength(u),h=s+1;h<p;h++){var m=e.referenceFramesEntry(i,h);if(c.frameType(m)!==r.FrameType.attribute){this.insertFrameRange(e,t,d,0,i,h,p);break}this.applyAttribute(e,t,f,m)}f instanceof HTMLSelectElement&&"_blazorSelectValue"in f&&v(f,f._blazorSelectValue)},e.prototype.insertComponent=function(e,t,n,r){var o=a.createAndInsertLogicalContainer(t,n),i=e.frameReader.componentId(r);this.attachComponentToElement(i,o)},e.prototype.insertText=function(e,t,n,r){var o=e.frameReader.textContent(r),i=document.createTextNode(o);a.insertLogicalChild(i,t,n)},e.prototype.insertMarkup=function(e,t,n,r){for(var o,i=a.createAndInsertLogicalContainer(t,n),u=e.frameReader.markupContent(r),s=(o=u,a.isSvgElement(t)?(l.innerHTML=o||" ",l):(c.innerHTML=o||" ",c.content)),f=0;s.firstChild;)a.insertLogicalChild(s.firstChild,i,f++)},e.prototype.applyAttribute=function(e,t,n,r){var o=e.frameReader,a=o.attributeName(r),i=o.attributeEventHandlerId(r);if(i){var u=m(a);this.eventDelegator.setListener(n,u,i,t)}else this.tryApplySpecialProperty(e,n,a,r)||n.setAttribute(a,o.attributeValue(r))},e.prototype.tryApplySpecialProperty=function(e,t,n,r){switch(n){case"value":return this.tryApplyValueProperty(e,t,r);case"checked":return this.tryApplyCheckedProperty(e,t,r);default:return!!n.startsWith("__internal_")&&(this.applyInternalAttribute(e,t,n.substring("__internal_".length),r),!0)}},e.prototype.applyInternalAttribute=function(e,t,n,r){var o=r?e.frameReader.attributeValue(r):null;if(n.startsWith("stopPropagation_")){var a=m(n.substring("stopPropagation_".length));this.eventDelegator.setStopPropagation(t,a,null!==o)}else{if(!n.startsWith("preventDefault_"))throw new Error("Unsupported internal attribute '"+n+"'");a=m(n.substring("preventDefault_".length));this.eventDelegator.setPreventDefault(t,a,null!==o)}},e.prototype.tryApplyValueProperty=function(e,t,n){var r=e.frameReader;if("INPUT"===t.tagName&&"time"===t.getAttribute("type")&&!t.getAttribute("step")){var o=n?r.attributeValue(n):null;if(o)return t.value=o.substring(0,5),!0}switch(t.tagName){case"INPUT":case"SELECT":case"TEXTAREA":var a=n?r.attributeValue(n):null;return t instanceof HTMLSelectElement?(v(t,a),t._blazorSelectValue=a):t.value=a,!0;case"OPTION":(a=n?r.attributeValue(n):null)||""===a?t.setAttribute("value",a):t.removeAttribute("value");var i=this.findClosestAncestorSelectElement(t);return i&&"_blazorSelectValue"in i&&i._blazorSelectValue===a&&(this.tryApplyValueProperty(e,i,n),delete i._blazorSelectValue),!0;default:return!1}},e.prototype.tryApplyCheckedProperty=function(e,t,n){if("INPUT"===t.tagName){var r=n?e.frameReader.attributeValue(n):null;return t.checked=null!==r,!0}return!1},e.prototype.findClosestAncestorSelectElement=function(e){for(;e;){if(e instanceof HTMLSelectElement)return e;e=e.parentElement}return null},e.prototype.insertFrameRange=function(e,t,n,r,o,a,i){for(var u=r,s=a;s<i;s++){var c=e.referenceFramesEntry(o,s);r+=this.insertFrame(e,t,n,r,o,c,s),s+=h(e,c)}return r-u},e}();function h(e,t){var n=e.frameReader;switch(n.frameType(t)){case r.FrameType.component:case r.FrameType.element:case r.FrameType.region:return n.subtreeLength(t)-1;default:return 0}}function m(e){if(e.startsWith("on"))return e.substring(2);throw new Error("Attribute should be an event name, but doesn't start with 'on'. Value: '"+e+"'")}function v(e,t){e.value=t||""}t.BrowserRenderer=p},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e){e[e.prependFrame=1]="prependFrame",e[e.removeFrame=2]="removeFrame",e[e.setAttribute=3]="setAttribute",e[e.removeAttribute=4]="removeAttribute",e[e.updateText=5]="updateText",e[e.stepIn=6]="stepIn",e[e.stepOut=7]="stepOut",e[e.updateMarkup=8]="updateMarkup",e[e.permutationListEntry=9]="permutationListEntry",e[e.permutationListEnd=10]="permutationListEnd"}(t.EditType||(t.EditType={})),function(e){e[e.element=1]="element",e[e.text=2]="text",e[e.attribute=3]="attribute",e[e.component=4]="component",e[e.region=5]="region",e[e.elementReferenceCapture=6]="elementReferenceCapture",e[e.markup=8]="markup"}(t.FrameType||(t.FrameType={}))},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(27),o=n(28),a=l(["abort","blur","change","error","focus","load","loadend","loadstart","mouseenter","mouseleave","progress","reset","scroll","submit","unload","DOMNodeInsertedIntoDocument","DOMNodeRemovedFromDocument"]),i=l(["click","dblclick","mousedown","mousemove","mouseup"]),u=function(){function e(t){this.onEvent=t,this.afterClickCallbacks=[];var n=++e.nextEventDelegatorId;this.eventsCollectionKey="_blazorEvents_"+n,this.eventInfoStore=new s(this.onGlobalEvent.bind(this))}return e.prototype.setListener=function(e,t,n,r){var o=this.getEventHandlerInfosForElement(e,!0),a=o.getHandler(t);if(a)this.eventInfoStore.update(a.eventHandlerId,n);else{var i={element:e,eventName:t,eventHandlerId:n,renderingComponentId:r};this.eventInfoStore.add(i),o.setHandler(t,i)}},e.prototype.removeListener=function(e){var t=this.eventInfoStore.remove(e);if(t){var n=t.element,r=this.getEventHandlerInfosForElement(n,!1);r&&r.removeHandler(t.eventName)}},e.prototype.notifyAfterClick=function(e){this.afterClickCallbacks.push(e),this.eventInfoStore.addGlobalListener("click")},e.prototype.setStopPropagation=function(e,t,n){this.getEventHandlerInfosForElement(e,!0).stopPropagation(t,n)},e.prototype.setPreventDefault=function(e,t,n){this.getEventHandlerInfosForElement(e,!0).preventDefault(t,n)},e.prototype.onGlobalEvent=function(e){if(e.target instanceof Element){for(var t,n,u=e.target,s=null,c=a.hasOwnProperty(e.type),l=!1;u;){var f=this.getEventHandlerInfosForElement(u,!1);if(f){var d=f.getHandler(e.type);if(d&&(t=u,n=e.type,!((t instanceof HTMLButtonElement||t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement||t instanceof HTMLSelectElement)&&i.hasOwnProperty(n)&&t.disabled))){s||(s=r.EventForDotNet.fromDOMEvent(e));var p=o.EventFieldInfo.fromEvent(d.renderingComponentId,e);this.onEvent(e,d.eventHandlerId,s,p)}f.stopPropagation(e.type)&&(l=!0),f.preventDefault(e.type)&&e.preventDefault()}u=c||l?null:u.parentElement}"click"===e.type&&this.afterClickCallbacks.forEach((function(t){return t(e)}))}},e.prototype.getEventHandlerInfosForElement=function(e,t){return e.hasOwnProperty(this.eventsCollectionKey)?e[this.eventsCollectionKey]:t?e[this.eventsCollectionKey]=new c:null},e.nextEventDelegatorId=0,e}();t.EventDelegator=u;var s=function(){function e(e){this.globalListener=e,this.infosByEventHandlerId={},this.countByEventName={}}return e.prototype.add=function(e){if(this.infosByEventHandlerId[e.eventHandlerId])throw new Error("Event "+e.eventHandlerId+" is already tracked");this.infosByEventHandlerId[e.eventHandlerId]=e,this.addGlobalListener(e.eventName)},e.prototype.addGlobalListener=function(e){if(this.countByEventName.hasOwnProperty(e))this.countByEventName[e]++;else{this.countByEventName[e]=1;var t=a.hasOwnProperty(e);document.addEventListener(e,this.globalListener,t)}},e.prototype.update=function(e,t){if(this.infosByEventHandlerId.hasOwnProperty(t))throw new Error("Event "+t+" is already tracked");var n=this.infosByEventHandlerId[e];delete this.infosByEventHandlerId[e],n.eventHandlerId=t,this.infosByEventHandlerId[t]=n},e.prototype.remove=function(e){var t=this.infosByEventHandlerId[e];if(t){delete this.infosByEventHandlerId[e];var n=t.eventName;0==--this.countByEventName[n]&&(delete this.countByEventName[n],document.removeEventListener(n,this.globalListener))}return t},e}(),c=function(){function e(){this.handlers={},this.preventDefaultFlags=null,this.stopPropagationFlags=null}return e.prototype.getHandler=function(e){return this.handlers.hasOwnProperty(e)?this.handlers[e]:null},e.prototype.setHandler=function(e,t){this.handlers[e]=t},e.prototype.removeHandler=function(e){delete this.handlers[e]},e.prototype.preventDefault=function(e,t){return void 0!==t&&(this.preventDefaultFlags=this.preventDefaultFlags||{},this.preventDefaultFlags[e]=t),!!this.preventDefaultFlags&&this.preventDefaultFlags[e]},e.prototype.stopPropagation=function(e,t){return void 0!==t&&(this.stopPropagationFlags=this.stopPropagationFlags||{},this.stopPropagationFlags[e]=t),!!this.stopPropagationFlags&&this.stopPropagationFlags[e]},e}();function l(e){var t={};return e.forEach((function(e){t[e]=!0})),t}},function(e,t,n){"use strict";var r=this&&this.__assign||function(){return(r=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var o in t=arguments[n])Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o]);return e}).apply(this,arguments)};Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){this.type=e,this.data=t}return e.fromDOMEvent=function(t){var n=t.target;switch(t.type){case"input":case"change":if(function(e){return-1!==i.indexOf(e.getAttribute("type"))}(n)){var o=function(e){var t=e.value,n=e.type;switch(n){case"date":case"datetime-local":case"month":return t;case"time":return 5===t.length?t+":00":t;case"week":return t}throw new Error("Invalid element type '"+n+"'.")}(n);return new e("change",{type:t.type,value:o})}var u=function(e){return!!e&&"INPUT"===e.tagName&&"checkbox"===e.getAttribute("type")}(n)?!!n.checked:n.value;return new e("change",{type:t.type,value:u});case"copy":case"cut":case"paste":return new e("clipboard",{type:t.type});case"drag":case"dragend":case"dragenter":case"dragleave":case"dragover":case"dragstart":case"drop":return new e("drag",function(e){return r(r({},a(e)),{dataTransfer:e.dataTransfer})}(t));case"focus":case"blur":case"focusin":case"focusout":return new e("focus",{type:t.type});case"keydown":case"keyup":case"keypress":return new e("keyboard",function(e){return{type:e.type,key:e.key,code:e.code,location:e.location,repeat:e.repeat,ctrlKey:e.ctrlKey,shiftKey:e.shiftKey,altKey:e.altKey,metaKey:e.metaKey}}(t));case"contextmenu":case"click":case"mouseover":case"mouseout":case"mousemove":case"mousedown":case"mouseup":case"dblclick":return new e("mouse",a(t));case"error":return new e("error",function(e){return{type:e.type,message:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno}}(t));case"loadstart":case"timeout":case"abort":case"load":case"loadend":case"progress":return new e("progress",function(e){return{type:e.type,lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total}}(t));case"touchcancel":case"touchend":case"touchmove":case"touchenter":case"touchleave":case"touchstart":return new e("touch",function(e){function t(e){for(var t=[],n=0;n<e.length;n++){var r=e[n];t.push({identifier:r.identifier,clientX:r.clientX,clientY:r.clientY,screenX:r.screenX,screenY:r.screenY,pageX:r.pageX,pageY:r.pageY})}return t}return{type:e.type,detail:e.detail,touches:t(e.touches),targetTouches:t(e.targetTouches),changedTouches:t(e.changedTouches),ctrlKey:e.ctrlKey,shiftKey:e.shiftKey,altKey:e.altKey,metaKey:e.metaKey}}(t));case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointerenter":case"pointerleave":case"pointermove":case"pointerout":case"pointerover":case"pointerup":return new e("pointer",function(e){return r(r({},a(e)),{pointerId:e.pointerId,width:e.width,height:e.height,pressure:e.pressure,tiltX:e.tiltX,tiltY:e.tiltY,pointerType:e.pointerType,isPrimary:e.isPrimary})}(t));case"wheel":case"mousewheel":return new e("wheel",function(e){return r(r({},a(e)),{deltaX:e.deltaX,deltaY:e.deltaY,deltaZ:e.deltaZ,deltaMode:e.deltaMode})}(t));default:return new e("unknown",{type:t.type})}},e}();function a(e){return{type:e.type,detail:e.detail,screenX:e.screenX,screenY:e.screenY,clientX:e.clientX,clientY:e.clientY,offsetX:e.offsetX,offsetY:e.offsetY,button:e.button,buttons:e.buttons,ctrlKey:e.ctrlKey,shiftKey:e.shiftKey,altKey:e.altKey,metaKey:e.metaKey}}t.EventForDotNet=o;var i=["date","datetime-local","month","time","week"]},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){this.componentId=e,this.fieldValue=t}return e.fromEvent=function(t,n){var r=n.target;if(r instanceof Element){var o=function(e){if(e instanceof HTMLInputElement)return e.type&&"checkbox"===e.type.toLowerCase()?{value:e.checked}:{value:e.value};if(e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement)return{value:e.value};return null}(r);if(o)return new e(t,o.value)}return null},e}();t.EventFieldInfo=r},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(3);function o(e){return"_bl_"+e}t.applyCaptureIdToElement=function(e,t){e.setAttribute(o(t),"")};r.DotNet.attachReviver((function(e,t){return t&&"object"==typeof t&&t.hasOwnProperty("__internalId")&&"string"==typeof t.__internalId?(n=t.__internalId,r="["+o(n)+"]",document.querySelector(r)):t;var n,r}))},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}};Object.defineProperty(t,"__esModule",{value:!0});var a=!1;t.showErrorNotification=function(){return r(this,void 0,void 0,(function(){var e;return o(this,(function(t){return(e=document.querySelector("#blazor-error-ui"))&&(e.style.display="block"),a||(a=!0,document.querySelectorAll("#blazor-error-ui .reload").forEach((function(e){e.onclick=function(e){location.reload(),e.preventDefault()}})),document.querySelectorAll("#blazor-error-ui .dismiss").forEach((function(e){e.onclick=function(e){var t=document.querySelector("#blazor-error-ui");t&&(t.style.display="none"),e.preventDefault()}}))),[2]}))}))}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=Math.pow(2,32),o=Math.pow(2,21)-1;function a(e,t){return e[t]+(e[t+1]<<8)+(e[t+2]<<16)+(e[t+3]<<24>>>0)}t.readInt32LE=function(e,t){return e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24},t.readUint32LE=a,t.readUint64LE=function(e,t){var n=a(e,t+4);if(n>o)throw new Error("Cannot read uint64 with high order part "+n+", because the result would exceed Number.MAX_SAFE_INTEGER.");return n*r+a(e,t)},t.readLEB128=function(e,t){for(var n=0,r=0,o=0;o<4;o++){var a=e[t+o];if(n|=(127&a)<<r,a<128)break;r+=7}return n},t.numLEB128Bytes=function(e){return e<128?1:e<16384?2:e<2097152?3:4}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r="function"==typeof TextDecoder?new TextDecoder("utf-8"):null;t.decodeUtf8=r?r.decode.bind(r):function(e){var t=0,n=e.length,r=[],o=[];for(;t<n;){var a=e[t++];if(0===a)break;if(0==(128&a))r.push(a);else if(192==(224&a)){var i=63&e[t++];r.push((31&a)<<6|i)}else if(224==(240&a)){i=63&e[t++];var u=63&e[t++];r.push((31&a)<<12|i<<6|u)}else if(240==(248&a)){i=63&e[t++],u=63&e[t++];var s=63&e[t++],c=(7&a)<<18|i<<12|u<<6|s;c>65535&&(c-=65536,r.push(c>>>10&1023|55296),c=56320|1023&c),r.push(c)}r.length>1024&&(o.push(String.fromCharCode.apply(null,r)),r.length=0)}return o.push(String.fromCharCode.apply(null,r)),o.join("")}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.shouldAutoStart=function(){return!(!document||!document.currentScript||"false"===document.currentScript.getAttribute("autostart"))}},,,,,,,,,,function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}},a=this&&this.__read||function(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,o,a=n.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(r=a.next()).done;)i.push(r.value)}catch(e){o={error:e}}finally{try{r&&!r.done&&(n=a.return)&&n.call(a)}finally{if(o)throw o.error}}return i};Object.defineProperty(t,"__esModule",{value:!0});var i=n(3);n(22);var u=n(17),s=n(44),c=n(4),l=n(47),f=n(33),d=n(18),p=n(48),h=n(49),m=n(50),v=!1;function y(e){return r(this,void 0,void 0,(function(){var t,n,f,y,b,g,w,E=this;return o(this,(function(_){switch(_.label){case 0:if(v)throw new Error("Blazor has already started.");return v=!0,d.setEventDispatcher((function(e,t){return i.DotNet.invokeMethodAsync("Microsoft.AspNetCore.Components.WebAssembly","DispatchEvent",e,JSON.stringify(t))})),t=u.setPlatform(s.monoPlatform),window.Blazor.platform=t,window.Blazor._internal.renderBatch=function(e,t){c.renderBatch(e,new l.SharedMemoryRenderBatch(t))},n=window.Blazor._internal.navigationManager.getBaseURI,f=window.Blazor._internal.navigationManager.getLocationHref,window.Blazor._internal.navigationManager.getUnmarshalledBaseURI=function(){return BINDING.js_string_to_mono_string(n())},window.Blazor._internal.navigationManager.getUnmarshalledLocationHref=function(){return BINDING.js_string_to_mono_string(f())},window.Blazor._internal.navigationManager.listenForNavigationEvents((function(e,t){return r(E,void 0,void 0,(function(){return o(this,(function(n){switch(n.label){case 0:return[4,i.DotNet.invokeMethodAsync("Microsoft.AspNetCore.Components.WebAssembly","NotifyLocationChanged",e,t)];case 1:return n.sent(),[2]}}))}))})),[4,m.BootConfigResult.initAsync()];case 1:return y=_.sent(),[4,Promise.all([p.WebAssemblyResourceLoader.initAsync(y.bootConfig,e||{}),h.WebAssemblyConfigLoader.initAsync(y)])];case 2:b=a.apply(void 0,[_.sent(),1]),g=b[0],_.label=3;case 3:return _.trys.push([3,5,,6]),[4,t.start(g)];case 4:return _.sent(),[3,6];case 5:throw w=_.sent(),new Error("Failed to start platform. Reason: "+w);case 6:return t.callEntryPoint(g.bootConfig.entryAssembly),[2]}}))}))}window.Blazor.start=y,f.shouldAutoStart()&&y().catch((function(e){"undefined"!=typeof Module&&Module.printErr?Module.printErr(e):console.error(e)}))},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}};Object.defineProperty(t,"__esModule",{value:!0});var a,i=n(3),u=n(45),s=n(30),c=n(46),l=Math.pow(2,32),f=Math.pow(2,21)-1;function d(e){return Module.HEAP32[e>>2]}t.monoPlatform={start:function(e){return new Promise((function(t,n){var l,f;u.attachDebuggerHotkey(e),window.Browser={init:function(){}},l=function(){window.Module=function(e,t,n){var l=this,f=e.bootConfig.resources,d=window.Module||{},h=["DEBUGGING ENABLED"];d.print=function(e){return h.indexOf(e)<0&&console.log(e)},d.printErr=function(e){console.error(e),s.showErrorNotification()},d.preRun=d.preRun||[],d.postRun=d.postRun||[],d.preloadPlugins=[];var y,b=e.loadResources(f.assembly,(function(e){return"_framework/"+e}),"assembly"),g=e.loadResources(f.pdb||{},(function(e){return"_framework/"+e}),"pdb"),w=e.loadResource("dotnet.wasm","_framework/dotnet.wasm",e.bootConfig.resources.runtime["dotnet.wasm"],"dotnetwasm");return e.bootConfig.resources.runtime.hasOwnProperty("dotnet.timezones.dat")&&(y=e.loadResource("dotnet.timezones.dat","_framework/dotnet.timezones.dat",e.bootConfig.resources.runtime["dotnet.timezones.dat"],"timezonedata")),d.instantiateWasm=function(e,t){return r(l,void 0,void 0,(function(){var n,r;return o(this,(function(o){switch(o.label){case 0:return o.trys.push([0,3,,4]),[4,w];case 1:return[4,v(o.sent(),e)];case 2:return n=o.sent(),[3,4];case 3:throw r=o.sent(),d.printErr(r),r;case 4:return t(n),[2]}}))})),[]},d.preRun.push((function(){a=cwrap("mono_wasm_add_assembly",null,["string","number","number"]),cwrap("mono_wasm_string_get_utf8","number",["number"]),MONO.loaded_files=[],y&&function(e){r(this,void 0,void 0,(function(){var t,n;return o(this,(function(r){switch(r.label){case 0:return t="blazor:timezonedata",addRunDependency(t),[4,e.response];case 1:return[4,r.sent().arrayBuffer()];case 2:return n=r.sent(),c.loadTimezoneData(n),removeRunDependency(t),[2]}}))}))}(y),b.forEach((function(e){return E(e,function(e,t){var n=e.lastIndexOf(".");if(n<0)throw new Error("No extension to replace in '"+e+"'");return e.substr(0,n)+t}(e.name,".dll"))})),g.forEach((function(e){return E(e,e.name)})),window.Blazor._internal.dotNetCriticalError=function(e){d.printErr(BINDING.conv_string(e)||"(null)")},window.Blazor._internal.getSatelliteAssemblies=function(t){var n=BINDING.mono_array_to_js_array(t),a=e.bootConfig.resources.satelliteResources;if(a){var i=Promise.all(n.filter((function(e){return a.hasOwnProperty(e)})).map((function(t){return e.loadResources(a[t],(function(e){return"_framework/"+e}),"assembly")})).reduce((function(e,t){return e.concat(t)}),new Array).map((function(e){return r(l,void 0,void 0,(function(){return o(this,(function(t){switch(t.label){case 0:return[4,e.response];case 1:return[2,t.sent().arrayBuffer()]}}))}))})));return BINDING.js_to_mono_obj(i.then((function(e){return e.length&&(window.Blazor._internal.readSatelliteAssemblies=function(){for(var t=BINDING.mono_obj_array_new(e.length),n=0;n<e.length;n++)BINDING.mono_obj_array_set(t,n,BINDING.js_typed_array_to_array(new Uint8Array(e[n])));return t}),e.length})))}return BINDING.js_to_mono_obj(Promise.resolve(0))}})),d.postRun.push((function(){var n,r,o;e.bootConfig.debugBuild&&e.bootConfig.cacheBootResources&&e.logToConsole(),e.purgeUnusedCacheEntriesAsync(),MONO.mono_wasm_setenv("MONO_URI_DOTNETRELATIVEORABSOLUTE","true"),cwrap("mono_wasm_load_runtime",null,["string","number"])("appBinDir",u.hasDebuggingEnabled()?-1:0),MONO.mono_wasm_runtime_ready(),n=m("Microsoft.AspNetCore.Components.WebAssembly","Microsoft.AspNetCore.Components.WebAssembly.Services.DefaultWebAssemblyJSRuntime","InvokeDotNet"),r=m("Microsoft.AspNetCore.Components.WebAssembly","Microsoft.AspNetCore.Components.WebAssembly.Services.DefaultWebAssemblyJSRuntime","BeginInvokeDotNet"),o=m("Microsoft.AspNetCore.Components.WebAssembly","Microsoft.AspNetCore.Components.WebAssembly.Services.DefaultWebAssemblyJSRuntime","EndInvokeJS"),i.DotNet.attachDispatcher({beginInvokeDotNetFromJS:function(e,t,n,o,a){if(!o&&!t)throw new Error("Either assemblyName or dotNetObjectId must have a non null value.");var i=o?o.toString():t;r(e?e.toString():null,i,n,a)},endInvokeJSFromDotNet:function(e,t,n){o(n)},invokeDotNetFromJS:function(e,t,r,o){return n(e||null,t,r?r.toString():null,o)}}),t()})),d;function E(e,t){return r(this,void 0,void 0,(function(){var r,i,u,s,c;return o(this,(function(o){switch(o.label){case 0:r="blazor:"+e.name,addRunDependency(r),o.label=1;case 1:return o.trys.push([1,3,,4]),[4,e.response.then((function(e){return e.arrayBuffer()}))];case 2:return i=o.sent(),u=new Uint8Array(i),s=Module._malloc(u.length),new Uint8Array(Module.HEAPU8.buffer,s,u.length).set(u),a(t,s,u.length),MONO.loaded_files.push((l=e.url,p.href=l,p.href)),[3,4];case 3:return c=o.sent(),n(c),[2];case 4:return removeRunDependency(r),[2]}var l}))}))}}(e,t,n),function(e){if("undefined"==typeof WebAssembly||!WebAssembly.validate)throw new Error("This browser does not support WebAssembly.");var t=Object.keys(e.bootConfig.resources.runtime).filter((function(e){return e.startsWith("dotnet.")&&e.endsWith(".js")}))[0],n=e.bootConfig.resources.runtime[t],r=document.createElement("script");if(r.src="_framework/"+t,r.defer=!0,e.bootConfig.cacheBootResources&&(r.integrity=n,r.crossOrigin="anonymous"),e.startOptions.loadBootResource){var o=e.startOptions.loadBootResource("dotnetjs",t,r.src,n);if("string"==typeof o)r.src=o;else if(o)throw new Error("For a dotnetjs resource, custom loaders must supply a URI string.")}document.body.appendChild(r)}(e)},f=document.createElement("script"),window.__wasmmodulecallback__=l,f.type="text/javascript",f.text="var Module; window.__wasmmodulecallback__(); delete window.__wasmmodulecallback__;",document.body.appendChild(f)}))},callEntryPoint:function(e){m("Microsoft.AspNetCore.Components.WebAssembly","Microsoft.AspNetCore.Components.WebAssembly.Hosting.EntrypointInvoker","InvokeEntrypoint")(e,null)},toUint8Array:function(e){var t=h(e),n=d(t);return new Uint8Array(Module.HEAPU8.buffer,t+4,n)},getArrayLength:function(e){return d(h(e))},getArrayEntryPtr:function(e,t,n){return h(e)+4+t*n},getObjectFieldsBaseAddress:function(e){return e+8},readInt16Field:function(e,t){return n=e+(t||0),Module.HEAP16[n>>1];var n},readInt32Field:function(e,t){return d(e+(t||0))},readUint64Field:function(e,t){return function(e){var t=e>>2,n=Module.HEAPU32[t+1];if(n>f)throw new Error("Cannot read uint64 with high order part "+n+", because the result would exceed Number.MAX_SAFE_INTEGER.");return n*l+Module.HEAPU32[t]}(e+(t||0))},readFloatField:function(e,t){return n=e+(t||0),Module.HEAPF32[n>>2];var n},readObjectField:function(e,t){return d(e+(t||0))},readStringField:function(e,t,n){var r=d(e+(t||0));if(0===r)return null;if(n){var o=BINDING.unbox_mono_obj(r);return"boolean"==typeof o?o?"":null:o}return BINDING.conv_string(r)},readStructField:function(e,t){return e+(t||0)}};var p=document.createElement("a");function h(e){return e+12}function m(e,t,n){var r="["+e+"] "+t+":"+n;return BINDING.bind_static_method(r)}function v(e,t){return r(this,void 0,void 0,(function(){var n,r;return o(this,(function(o){switch(o.label){case 0:if("function"!=typeof WebAssembly.instantiateStreaming)return[3,4];o.label=1;case 1:return o.trys.push([1,3,,4]),[4,WebAssembly.instantiateStreaming(e.response,t)];case 2:return[2,o.sent().instance];case 3:return n=o.sent(),console.info("Streaming compilation failed. Falling back to ArrayBuffer instantiation. ",n),[3,4];case 4:return[4,e.response.then((function(e){return e.arrayBuffer()}))];case 5:return r=o.sent(),[4,WebAssembly.instantiate(r,t)];case 6:return[2,o.sent().instance]}}))}))}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=window.chrome&&navigator.userAgent.indexOf("Edge")<0,o=!1;function a(){return o&&r}t.hasDebuggingEnabled=a,t.attachDebuggerHotkey=function(e){o=!!e.bootConfig.resources.pdb;var t=navigator.platform.match(/^Mac/i)?"Cmd":"Alt";a()&&console.info("Debugging hotkey: Shift+"+t+"+D (when application has focus)"),document.addEventListener("keydown",(function(e){var t;e.shiftKey&&(e.metaKey||e.altKey)&&"KeyD"===e.code&&(o?r?((t=document.createElement("a")).href="_framework/debug?url="+encodeURIComponent(location.href),t.target="_blank",t.rel="noopener noreferrer",t.click()):console.error("Currently, only Microsoft Edge (80+), or Google Chrome, are supported for debugging."):console.error("Cannot start debugging, because the application was not compiled with debugging enabled."))}))}},function(e,t,n){"use strict";var r=this&&this.__values||function(e){var t="function"==typeof Symbol&&Symbol.iterator,n=t&&e[t],r=0;if(n)return n.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},o=this&&this.__read||function(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,o,a=n.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(r=a.next()).done;)i.push(r.value)}catch(e){o={error:e}}finally{try{r&&!r.done&&(n=a.return)&&n.call(a)}finally{if(o)throw o.error}}return i};Object.defineProperty(t,"__esModule",{value:!0});var a=n(31),i=n(32);t.loadTimezoneData=function(e){var t,n,u=new Uint8Array(e),s=a.readInt32LE(u,0);u=u.slice(4);var c=i.decodeUtf8(u.slice(0,s)),l=JSON.parse(c);u=u.slice(s),Module.FS_createPath("/","zoneinfo",!0,!0),new Set(l.map((function(e){return e[0].split("/")[0]}))).forEach((function(e){return Module.FS_createPath("/zoneinfo",e,!0,!0)}));try{for(var f=r(l),d=f.next();!d.done;d=f.next()){var p=o(d.value,2),h=p[0],m=p[1],v=u.slice(0,m);Module.FS_createDataFile("/zoneinfo/"+h,null,v,!0,!0,!0),u=u.slice(m)}}catch(e){t={error:e}}finally{try{d&&!d.done&&(n=f.return)&&n.call(f)}finally{if(t)throw t.error}}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(17),o=function(){function e(e){this.batchAddress=e,this.arrayRangeReader=a,this.arrayBuilderSegmentReader=i,this.diffReader=u,this.editReader=s,this.frameReader=c}return e.prototype.updatedComponents=function(){return r.platform.readStructField(this.batchAddress,0)},e.prototype.referenceFrames=function(){return r.platform.readStructField(this.batchAddress,a.structLength)},e.prototype.disposedComponentIds=function(){return r.platform.readStructField(this.batchAddress,2*a.structLength)},e.prototype.disposedEventHandlerIds=function(){return r.platform.readStructField(this.batchAddress,3*a.structLength)},e.prototype.updatedComponentsEntry=function(e,t){return l(e,t,u.structLength)},e.prototype.referenceFramesEntry=function(e,t){return l(e,t,c.structLength)},e.prototype.disposedComponentIdsEntry=function(e,t){var n=l(e,t,4);return r.platform.readInt32Field(n)},e.prototype.disposedEventHandlerIdsEntry=function(e,t){var n=l(e,t,8);return r.platform.readUint64Field(n)},e}();t.SharedMemoryRenderBatch=o;var a={structLength:8,values:function(e){return r.platform.readObjectField(e,0)},count:function(e){return r.platform.readInt32Field(e,4)}},i={structLength:12,values:function(e){var t=r.platform.readObjectField(e,0),n=r.platform.getObjectFieldsBaseAddress(t);return r.platform.readObjectField(n,0)},offset:function(e){return r.platform.readInt32Field(e,4)},count:function(e){return r.platform.readInt32Field(e,8)}},u={structLength:4+i.structLength,componentId:function(e){return r.platform.readInt32Field(e,0)},edits:function(e){return r.platform.readStructField(e,4)},editsEntry:function(e,t){return l(e,t,s.structLength)}},s={structLength:20,editType:function(e){return r.platform.readInt32Field(e,0)},siblingIndex:function(e){return r.platform.readInt32Field(e,4)},newTreeIndex:function(e){return r.platform.readInt32Field(e,8)},moveToSiblingIndex:function(e){return r.platform.readInt32Field(e,8)},removedAttributeName:function(e){return r.platform.readStringField(e,16)}},c={structLength:36,frameType:function(e){return r.platform.readInt16Field(e,4)},subtreeLength:function(e){return r.platform.readInt32Field(e,8)},elementReferenceCaptureId:function(e){return r.platform.readStringField(e,16)},componentId:function(e){return r.platform.readInt32Field(e,12)},elementName:function(e){return r.platform.readStringField(e,16)},textContent:function(e){return r.platform.readStringField(e,16)},markupContent:function(e){return r.platform.readStringField(e,16)},attributeName:function(e){return r.platform.readStringField(e,16)},attributeValue:function(e){return r.platform.readStringField(e,24,!0)},attributeEventHandlerId:function(e){return r.platform.readUint64Field(e,8)}};function l(e,t,n){return r.platform.getArrayEntryPtr(e,t,n)}},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}};Object.defineProperty(t,"__esModule",{value:!0});var a=n(7),i=function(){function e(e,t,n){this.bootConfig=e,this.cacheIfUsed=t,this.startOptions=n,this.usedCacheKeys={},this.networkLoads={},this.cacheLoads={}}return e.initAsync=function(t,n){return r(this,void 0,void 0,(function(){var r;return o(this,(function(o){switch(o.label){case 0:return[4,u(t)];case 1:return r=o.sent(),[2,new e(t,r,n)]}}))}))},e.prototype.loadResources=function(e,t,n){var r=this;return Object.keys(e).map((function(o){return r.loadResource(o,t(o),e[o],n)}))},e.prototype.loadResource=function(e,t,n,r){return{name:e,url:t,response:this.cacheIfUsed?this.loadResourceWithCaching(this.cacheIfUsed,e,t,n,r):this.loadResourceWithoutCaching(e,t,n,r)}},e.prototype.logToConsole=function(){var e=Object.values(this.cacheLoads),t=Object.values(this.networkLoads),n=s(e),r=s(t),o=n+r;if(0!==o){var a=this.bootConfig.linkerEnabled?"%c":"\n%cThis application was built with linking (tree shaking) disabled. Published applications will be significantly smaller.";console.groupCollapsed("%cblazor%c Loaded "+c(o)+" resources"+a,"background: purple; color: white; padding: 1px 3px; border-radius: 3px;","font-weight: bold;","font-weight: normal;"),e.length&&(console.groupCollapsed("Loaded "+c(n)+" resources from cache"),console.table(this.cacheLoads),console.groupEnd()),t.length&&(console.groupCollapsed("Loaded "+c(r)+" resources from network"),console.table(this.networkLoads),console.groupEnd()),console.groupEnd()}},e.prototype.purgeUnusedCacheEntriesAsync=function(){return r(this,void 0,void 0,(function(){var e,t,n,a=this;return o(this,(function(i){switch(i.label){case 0:return(e=this.cacheIfUsed)?[4,e.keys()]:[3,3];case 1:return t=i.sent(),n=t.map((function(t){return r(a,void 0,void 0,(function(){return o(this,(function(n){switch(n.label){case 0:return t.url in this.usedCacheKeys?[3,2]:[4,e.delete(t)];case 1:n.sent(),n.label=2;case 2:return[2]}}))}))})),[4,Promise.all(n)];case 2:i.sent(),i.label=3;case 3:return[2]}}))}))},e.prototype.loadResourceWithCaching=function(e,t,n,i,u){return r(this,void 0,void 0,(function(){var r,s,c,l;return o(this,(function(o){switch(o.label){case 0:if(!i||0===i.length)throw new Error("Content hash is required");r=a.toAbsoluteUri(n+"."+i),this.usedCacheKeys[r]=!0,o.label=1;case 1:return o.trys.push([1,3,,4]),[4,e.match(r)];case 2:return s=o.sent(),[3,4];case 3:return o.sent(),[3,4];case 4:return s?(c=parseInt(s.headers.get("content-length")||"0"),this.cacheLoads[t]={responseBytes:c},[2,s]):[3,5];case 5:return[4,this.loadResourceWithoutCaching(t,n,i,u)];case 6:return l=o.sent(),this.addToCacheAsync(e,t,r,l),[2,l]}}))}))},e.prototype.loadResourceWithoutCaching=function(e,t,n,r){if(this.startOptions.loadBootResource){var o=this.startOptions.loadBootResource(r,e,t,n);if(o instanceof Promise)return o;"string"==typeof o&&(t=o)}return fetch(t,{cache:"no-cache",integrity:this.bootConfig.cacheBootResources?n:void 0})},e.prototype.addToCacheAsync=function(e,t,n,a){return r(this,void 0,void 0,(function(){var r,i,u,s;return o(this,(function(o){switch(o.label){case 0:return[4,a.clone().arrayBuffer()];case 1:r=o.sent(),i=function(e){if("undefined"!=typeof performance)return performance.getEntriesByName(e)[0]}(a.url),u=i&&i.encodedBodySize||void 0,this.networkLoads[t]={responseBytes:u},s=new Response(r,{headers:{"content-type":a.headers.get("content-type")||"","content-length":(u||a.headers.get("content-length")||"").toString()}}),o.label=2;case 2:return o.trys.push([2,4,,5]),[4,e.put(n,s)];case 3:return o.sent(),[3,5];case 4:return o.sent(),[3,5];case 5:return[2]}}))}))},e}();function u(e){return r(this,void 0,void 0,(function(){var t,n;return o(this,(function(r){switch(r.label){case 0:if(!e.cacheBootResources||"undefined"==typeof caches)return[2,null];t=document.baseURI.substring(document.location.origin.length),n="blazor-resources-"+t,r.label=1;case 1:return r.trys.push([1,3,,4]),[4,caches.open(n)];case 2:return[2,r.sent()||null];case 3:return r.sent(),[2,null];case 4:return[2]}}))}))}function s(e){return e.reduce((function(e,t){return e+(t.responseBytes||0)}),0)}function c(e){return(e/1048576).toFixed(2)+" MB"}t.WebAssemblyResourceLoader=i},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}};Object.defineProperty(t,"__esModule",{value:!0});var a=function(){function e(){}return e.initAsync=function(e){return r(this,void 0,void 0,(function(){function t(e){return r(this,void 0,void 0,(function(){var t,n;return o(this,(function(r){switch(r.label){case 0:return[4,fetch(e,{method:"GET",credentials:"include",cache:"no-cache"})];case 1:return t=r.sent(),n=Uint8Array.bind,[4,t.arrayBuffer()];case 2:return[2,new(n.apply(Uint8Array,[void 0,r.sent()]))]}}))}))}var n,a=this;return o(this,(function(i){switch(i.label){case 0:return window.Blazor._internal.getApplicationEnvironment=function(){return BINDING.js_string_to_mono_string(e.applicationEnvironment)},[4,Promise.all((e.bootConfig.config||[]).filter((function(t){return"appsettings.json"===t||t==="appsettings."+e.applicationEnvironment+".json"})).map((function(e){return r(a,void 0,void 0,(function(){var n;return o(this,(function(r){switch(r.label){case 0:return n={name:e},[4,t(e)];case 1:return[2,(n.content=r.sent(),n)]}}))}))})))];case 1:return n=i.sent(),window.Blazor._internal.getConfig=function(e){var t=BINDING.conv_string(e),r=n.find((function(e){return e.name===t}));return r?BINDING.js_typed_array_to_array(r.content):void 0},[2]}}))}))},e}();t.WebAssemblyConfigLoader=a},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,a){function i(e){try{s(r.next(e))}catch(e){a(e)}}function u(e){try{s(r.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,u)}s((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){i.label=a[1];break}if(6===a[0]&&i.label<o[1]){i.label=o[1],o=a;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(a);break}o[2]&&i.ops.pop(),i.trys.pop();continue}a=t.call(e,i)}catch(e){a=[6,e],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,u])}}};Object.defineProperty(t,"__esModule",{value:!0});var a=function(){function e(e,t){this.bootConfig=e,this.applicationEnvironment=t}return e.initAsync=function(){return r(this,void 0,void 0,(function(){var t,n;return o(this,(function(r){switch(r.label){case 0:return[4,fetch("_framework/blazor.boot.json",{method:"GET",credentials:"include",cache:"no-cache"})];case 1:return t=r.sent(),n=t.headers.get("Blazor-Environment")||"Production",[4,t.json()];case 2:return[2,new e(r.sent(),n)]}}))}))},e}();t.BootConfigResult=a}]); \ No newline at end of file
diff --git a/src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts b/src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts
index 5836de603d..ae1e93c6bd 100644
--- a/src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts
+++ b/src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts
@@ -142,7 +142,7 @@ function addScriptTagsToDocument(resourceLoader: WebAssemblyResourceLoader) {
.filter(n => n.startsWith('dotnet.') && n.endsWith('.js'))[0];
const dotnetJsContentHash = resourceLoader.bootConfig.resources.runtime[dotnetJsResourceName];
const scriptElem = document.createElement('script');
- scriptElem.src = `_framework/wasm/${dotnetJsResourceName}`;
+ scriptElem.src = `_framework/${dotnetJsResourceName}`;
scriptElem.defer = true;
// For consistency with WebAssemblyResourceLoader, we only enforce SRI if caching is allowed
@@ -204,11 +204,11 @@ function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourceLoade
// Begin loading the .dll/.pdb/.wasm files, but don't block here. Let other loading processes run in parallel.
const dotnetWasmResourceName = 'dotnet.wasm';
- const assembliesBeingLoaded = resourceLoader.loadResources(resources.assembly, filename => `_framework/_bin/${filename}`, 'assembly');
- const pdbsBeingLoaded = resourceLoader.loadResources(resources.pdb || {}, filename => `_framework/_bin/${filename}`, 'pdb');
+ const assembliesBeingLoaded = resourceLoader.loadResources(resources.assembly, filename => `_framework/${filename}`, 'assembly');
+ const pdbsBeingLoaded = resourceLoader.loadResources(resources.pdb || {}, filename => `_framework/${filename}`, 'pdb');
const wasmBeingLoaded = resourceLoader.loadResource(
/* name */ dotnetWasmResourceName,
- /* url */ `_framework/wasm/${dotnetWasmResourceName}`,
+ /* url */ `_framework/${dotnetWasmResourceName}`,
/* hash */ resourceLoader.bootConfig.resources.runtime[dotnetWasmResourceName],
/* type */ 'dotnetwasm');
@@ -217,7 +217,7 @@ function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourceLoade
if (resourceLoader.bootConfig.resources.runtime.hasOwnProperty(dotnetTimeZoneResourceName)) {
timeZoneResource = resourceLoader.loadResource(
dotnetTimeZoneResourceName,
- `_framework/wasm/${dotnetTimeZoneResourceName}`,
+ `_framework/${dotnetTimeZoneResourceName}`,
resourceLoader.bootConfig.resources.runtime[dotnetTimeZoneResourceName],
'timezonedata');
}
@@ -267,7 +267,7 @@ function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourceLoade
if (satelliteResources) {
const resourcePromises = Promise.all(culturesToLoad
.filter(culture => satelliteResources.hasOwnProperty(culture))
- .map(culture => resourceLoader.loadResources(satelliteResources[culture], fileName => `_framework/_bin/${fileName}`, 'assembly'))
+ .map(culture => resourceLoader.loadResources(satelliteResources[culture], fileName => `_framework/${fileName}`, 'assembly'))
.reduce((previous, next) => previous.concat(next), new Array<LoadingResource>())
.map(async resource => (await resource.response).arrayBuffer()));
diff --git a/src/Components/WebAssembly/Build/src/Microsoft.AspNetCore.Components.WebAssembly.Build.csproj b/src/Components/WebAssembly/Build/src/Microsoft.AspNetCore.Components.WebAssembly.Build.csproj
deleted file mode 100644
index d15e4ca761..0000000000
--- a/src/Components/WebAssembly/Build/src/Microsoft.AspNetCore.Components.WebAssembly.Build.csproj
+++ /dev/null
@@ -1,112 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
- <PropertyGroup>
- <TargetFrameworks>$(DefaultNetCoreTargetFramework);net46</TargetFrameworks>
- <TargetName>Microsoft.AspNetCore.Components.WebAssembly.Build.Tasks</TargetName>
- <AssemblyName>Microsoft.AspNetCore.Components.WebAssembly.Build</AssemblyName>
- <Description>Build mechanism for ASP.NET Core Blazor WebAssembly applications.</Description>
- <IsShippingPackage>true</IsShippingPackage>
- <GenerateDependencyFile>false</GenerateDependencyFile>
- <GenerateDocumentationFile>true</GenerateDocumentationFile>
- </PropertyGroup>
-
- <!-- Pack settings -->
- <PropertyGroup>
- <!-- Producing this package requires building with NodeJS enabled. -->
- <IsPackable Condition="'$(BuildNodeJS)' == 'false'">false</IsPackable>
- <NoPackageAnalysis>true</NoPackageAnalysis>
- <NuspecFile>Microsoft.AspNetCore.Components.WebAssembly.Build.nuspec</NuspecFile>
- </PropertyGroup>
-
- <ItemGroup>
- <NuspecProperty Include="configuration=$(Configuration)" />
- <NuspecProperty Include="taskskDir=$(OutputPath)tools" />
- <NuspecProperty Include="MicrosoftAspNetCoreComponentsWebAssemblyRuntimePackageVersion=$(MicrosoftAspNetCoreComponentsWebAssemblyRuntimePackageVersion)" />
- <NuspecProperty Include="PackageThirdPartyNoticesFile=$(PackageThirdPartyNoticesFile)" />
- </ItemGroup>
-
- <ItemGroup>
- <InternalsVisibleTo Include="Microsoft.AspNetCore.Components.WebAssembly.Build.Tests" />
- </ItemGroup>
-
- <ItemGroup>
- <!-- Add a project dependency without reference output assemblies to enforce build order -->
- <!-- Applying workaround for https://github.com/microsoft/msbuild/issues/2661 and https://github.com/dotnet/sdk/issues/952 -->
- <ProjectReference
- Include="$(RepoRoot)src\Components\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj"
- ReferenceOutputAssemblies="false"
- SkipGetTargetFrameworkProperties="true"
- UndefineProperties="TargetFramework"
- Private="false"
- Condition="'$(BuildNodeJS)' != 'false' and '$(BuildingInsideVisualStudio)' != 'true'" />
-
- <ProjectReference
- Include="..\..\Compression\src\Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression.csproj"
- ReferenceOutputAssemblies="false"
- Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'" />
-
- <Reference Include="Microsoft.Build.Framework" ExcludeAssets="Runtime" />
- <Reference Include="Microsoft.Build.Utilities.Core" ExcludeAssets="Runtime" />
- <Reference Include="System.Reflection.Metadata" Condition="'$(TargetFramework)' == 'net46'" />
- </ItemGroup>
-
- <Target Name="CopyBuildTask" BeforeTargets="Build" Condition="'$(DotNetBuildFromSource)' != 'true' AND '$(IsInnerBuild)' != 'true'">
- <!--
- The task produced by this project is referenced within this solution. When building, Visual Studio will lock up the assembly.
- Any attempts to overwrite the binary with a newer version will fail. This is particularly grating if a developer "Rebuilds" the project
- after an initial build since that would always attempt to overwrite the tasks dll
-
- This target attempts to make this solution more usable at the cost of a more onerous inner-loop build of the Blazor.Build tasks.
- We'll copy the tasks to a location other that than the build output and use that in the Blazor.Build.targets. In the most common
- case where these tasks aren't being worked on, everything should work great. However, if you're attemping to modify these tasks,
- you will need to manaully stop MSBuild.exe processes
- -->
-
- <ItemGroup>
- <_NetCoreFilesToCopy Include="$(OutputPath)$(DefaultNetCoreTargetFramework)\*" TargetPath="netcoreapp\" />
- <_DesktopFilesToCopy Include="$(OutputPath)net46\*" TargetPath="netfx\" />
- <_AllFilesToCopy Include="@(_NetCoreFilesToCopy);@(_DesktopFilesToCopy)" />
- </ItemGroup>
-
- <Error Text="No files found in $(OutputPath)$(DefaultNetCoreTargetFramework)" Condition="@(_NetCoreFilesToCopy->Count()) == 0" />
- <Error Text="No files found in $(OutputPath)net46" Condition="@(_DesktopFilesToCopy->Count()) == 0" />
-
- <Copy SourceFiles="@(_AllFilesToCopy)" DestinationFiles="@(_AllFilesToCopy->'$(OutputPath)tools\%(TargetPath)%(FileName)%(Extension)')" SkipUnchangedFiles="true" Retries="1" ContinueOnError="true">
- <Output TaskParameter="CopiedFiles" ItemName="FileWrites" />
- </Copy>
- </Target>
-
- <ItemGroup>
- <_BrotliToolPathInput Include="..\..\Compression\src\Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression.csproj" />
- <_BrotliToolPathInput Include="..\..\Compression\src\*.cs" />
- <_BrotliToolPathInput Include="..\..\Compression\src\*.runtimeconfig.json" />
- <_BrotliToolPathOutput Include="$(MSBuildThisFileDirectory)bin\$(Configuration)\tools\compression\blazor-brotli.dll" />
- </ItemGroup>
-
- <Target
- Name="GetBrotliTools"
- BeforeTargets="Build;GenerateNuspec"
- Inputs="@(_BrotliToolPathInput)"
- Outputs="@(_BrotliToolPathOutput)"
- Condition="'$(DotNetBuildFromSource)' != 'true'">
- <ItemGroup>
- <_BrotliToolsPath Include="$(MSBuildThisFileDirectory)bin\$(Configuration)\tools\compression\" />
- </ItemGroup>
-
- <PropertyGroup>
- <_BrotliToolsOutputPath>@(_BrotliToolsPath->'%(FullPath)')</_BrotliToolsOutputPath>
- </PropertyGroup>
-
- <ItemGroup>
- <NuspecProperty Include="brotliDir=$(_BrotliToolsOutputPath)" />
- </ItemGroup>
-
- <MSBuild
- Projects="..\..\Compression\src\Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression.csproj"
- Targets="Publish"
- Properties="Configuration=$(Configuration);TargetFramework=$(DefaultNetCoreTargetFramework);PublishDir=$(_BrotliToolsOutputPath)">
- </MSBuild>
-
- </Target>
-
-</Project>
diff --git a/src/Components/WebAssembly/Build/src/Microsoft.AspNetCore.Components.WebAssembly.Build.nuspec b/src/Components/WebAssembly/Build/src/Microsoft.AspNetCore.Components.WebAssembly.Build.nuspec
deleted file mode 100644
index 9b8aa9ad3a..0000000000
--- a/src/Components/WebAssembly/Build/src/Microsoft.AspNetCore.Components.WebAssembly.Build.nuspec
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
- <metadata>
- $CommonMetadataElements$
- <dependencies>
- <dependency id="Microsoft.AspNetCore.Components.WebAssembly.Runtime" version="$MicrosoftAspNetCoreComponentsWebAssemblyRuntimePackageVersion$" include="all" />
- </dependencies>
- </metadata>
- <files>
- $CommonFileElements$
- <file src="$PackageThirdPartyNoticesFile$" target=".\THIRD-PARTY-NOTICES.txt" />
- <file src="build\**" target="build" />
- <file src="$brotliDir$blazor-brotli.dll" target="tools/compression" />
- <file src="$brotliDir$blazor-brotli.runtimeconfig.json" target="tools/compression" />
- <file src="targets\**" target="targets" />
- <file src="$taskskDir$\**" target="tools/" />
- <file src="..\..\..\Web.JS\dist\$configuration$\blazor.webassembly.js" target="tools/blazor" />
- </files>
-</package>
diff --git a/src/Components/WebAssembly/Build/src/ReferenceBlazorBuildFromSource.props b/src/Components/WebAssembly/Build/src/ReferenceBlazorBuildFromSource.props
deleted file mode 100644
index 2083ec2891..0000000000
--- a/src/Components/WebAssembly/Build/src/ReferenceBlazorBuildFromSource.props
+++ /dev/null
@@ -1,27 +0,0 @@
-<Project>
- <!--
- Importing this file is equivalent to having:
- <PackageDependency Include="Microsoft.AspNetCore.Blazor.Build" />
- ... except it's much more convenient when working in this repo, because it consumes the
- Blazor.Build targets/exe directly without needing this project to be packed into a .nupkg.
-
- This is only intended for use by other projects in this repo.
- -->
-
- <PropertyGroup>
- <ComponentsRoot Condition="'$(ComponentsRoot)'==''">$(MSBuildThisFileDirectory)..\..\..\</ComponentsRoot>
- <BlazorBuildConfiguration Condition="'$(BlazorBuildConfiguration)'==''">$(Configuration)</BlazorBuildConfiguration>
-
- <_BlazorJsPath>$(ComponentsRoot)Web.JS\dist\$(BlazorBuildConfiguration)\blazor.webassembly.js</_BlazorJsPath>
- <_BlazorJsMapPath>$(ComponentsRoot)Web.JS\dist\$(BlazorBuildConfiguration)\blazor.webassembly.js.map</_BlazorJsMapPath>
- <_BlazorToolsDir>$(MSBuildThisFileDirectory)bin\$(BlazorBuildConfiguration)\tools\</_BlazorToolsDir>
- </PropertyGroup>
-
- <Target Name="Check_BlazorJSFiles" BeforeTargets="Build" Condition="'$(ExcludeFromBuild)' != 'true'">
- <Error Text="blazor.webassembly.js file could not be found at $(_BlazorJsPath)" Condition="!Exists($(_BlazorJsPath))" />
- </Target>
-
- <Import Project="$(MSBuildThisFileDirectory)targets/All.props" />
- <Import Project="$(MSBuildThisFileDirectory)targets/All.targets" />
-
-</Project>
diff --git a/src/Components/WebAssembly/Build/src/ReferenceFromSource.props b/src/Components/WebAssembly/Build/src/ReferenceFromSource.props
deleted file mode 100644
index decf4343ee..0000000000
--- a/src/Components/WebAssembly/Build/src/ReferenceFromSource.props
+++ /dev/null
@@ -1,48 +0,0 @@
-<Project>
-
- <Import Project="ReferenceBlazorBuildFromSource.props" />
-
- <!--
- Debugging support using blazor-devserver serve.
-
- A few things to note here:
- - We have to use dotnet exec to avoid launching another process and confusing the debugger.
- - Since we're doing dotnet exec, it won't automatically rebuild the DevServer project.
- - $(AdditionalRunArguments) needs to be defined before importing this file.
- -->
- <PropertyGroup>
- <RunCommand>dotnet</RunCommand>
- <_BlazorCliLocation>$(MSBuildThisFileDirectory)../../DevServer/src/bin/$(Configuration)/$(DefaultNetCoreTargetFramework)/blazor-devserver.dll</_BlazorCliLocation>
- <RunArguments>exec &quot;$(_BlazorCliLocation)&quot; serve --applicationpath &quot;$(MSBuildProjectDirectory)/$(OutputPath)$(TargetFileName)&quot; $(AdditionalRunArguments)</RunArguments>
- </PropertyGroup>
-
- <ItemGroup>
- <Reference Include="Microsoft.AspNetCore.Components.WebAssembly.Runtime" />
- </ItemGroup>
-
- <Target Name="_BuildBlazorBuildProject" BeforeTargets="ResolveProjectReferences" Condition="'$(NoBuild)' != 'true'">
- <!--
- The Blazor.Build project cross-compiles and we need the output of all TFMs to be available in the build output.
- We can't represent this in any good way using ProjectReference elements, but we can try and build it instead.
- -->
- <MSBuild Projects="$(MSBuildThisFileDirectory)Microsoft.AspNetCore.Components.WebAssembly.Build.csproj" />
- </Target>
-
- <!-- This is used as a P2P when building the repo. Normal Blazor projects will get this as a reference through the Blazor.Build package -->
- <ItemGroup>
- <!-- Ensures these projects are built before the consuming project, but without
- adding a runtime dependency on the .dll (to be equivalent to a <PackageDependency>
- given that the packed version of this project wouldn't add a .dll reference) -->
- <ProjectReference Include="$(MSBuildThisFileDirectory)Microsoft.AspNetCore.Components.WebAssembly.Build.csproj">
- <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
- <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
- <Properties>TargetFramework=$(DefaultNetCoreTargetFramework)</Properties>
- </ProjectReference>
- <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\DevServer\src\Microsoft.AspNetCore.Components.WebAssembly.DevServer.csproj">
- <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
- <!-- Optimization. Do not require framework compatibility between these projects. -->
- <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
- <UndefineProperties>TargetFramework</UndefineProperties>
- </ProjectReference>
- </ItemGroup>
-</Project>
diff --git a/src/Components/WebAssembly/Build/src/Tasks/BlazorGetFileHash.cs b/src/Components/WebAssembly/Build/src/Tasks/BlazorGetFileHash.cs
deleted file mode 100644
index f10f53a748..0000000000
--- a/src/Components/WebAssembly/Build/src/Tasks/BlazorGetFileHash.cs
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Security.Cryptography;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-
-namespace Microsoft.Build.Tasks
-{
- /// <summary>
- /// Computes the checksum for a single file.
- /// </summary>
- public sealed class BlazorGetFileHash : Task
- {
- internal const string _defaultFileHashAlgorithm = "SHA256";
- internal const string _hashEncodingBase64 = "base64";
-
- /// <summary>
- /// The files to be hashed.
- /// </summary>
- [Required]
- public ITaskItem[] Files { get; set; }
-
- /// <summary>
- /// The algorithm. Allowed values: SHA256, SHA384, SHA512. Default = SHA256.
- /// </summary>
- public string Algorithm { get; set; } = _defaultFileHashAlgorithm;
-
- /// <summary>
- /// The metadata name where the hash is stored in each item. Defaults to "FileHash".
- /// </summary>
- public string MetadataName { get; set; } = "FileHash";
-
- /// <summary>
- /// The encoding to use for generated hashs. Defaults to "hex". Allowed values = "base64".
- /// </summary>
- public string HashEncoding { get; set; } = _hashEncodingBase64;
-
- /// <summary>
- /// The hash of the file. This is only set if there was one item group passed in.
- /// </summary>
- [Output]
- public string Hash { get; set; }
-
- /// <summary>
- /// The input files with additional metadata set to include the file hash.
- /// </summary>
- [Output]
- public ITaskItem[] Items { get; set; }
-
- public override bool Execute()
- {
- if (!SupportsAlgorithm(Algorithm))
- {
- Log.LogError("Unrecognized HashAlgorithm {0}", Algorithm);
- return false;
- }
-
- System.Threading.Tasks.Parallel.ForEach(Files, file =>
- {
- if (!File.Exists(file.ItemSpec))
- {
- Log.LogError("File not found '{0}", file.ItemSpec);
- }
- });
-
- if (Log.HasLoggedErrors)
- {
- return false;
- }
-
- System.Threading.Tasks.Parallel.ForEach(Files, file =>
- {
- var hash = ComputeHash(Algorithm, file.ItemSpec);
- file.SetMetadata("FileHashAlgorithm", Algorithm);
- file.SetMetadata(MetadataName, EncodeHash(hash));
- });
-
- Items = Files;
-
- if (Files.Length == 1)
- {
- Hash = Files[0].GetMetadata(MetadataName);
- }
-
- return !Log.HasLoggedErrors;
- }
-
- internal static string EncodeHash(byte[] hash)
- {
- return Convert.ToBase64String(hash);
- }
-
- internal static bool SupportsAlgorithm(string algorithmName)
- => _supportedAlgorithms.Contains(algorithmName);
-
- internal static byte[] ComputeHash(string algorithmName, string filePath)
- {
- using (var stream = File.OpenRead(filePath))
- using (var algorithm = CreateAlgorithm(algorithmName))
- {
- return algorithm.ComputeHash(stream);
- }
- }
-
- private static readonly HashSet<string> _supportedAlgorithms
- = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
- {
- "SHA256",
- "SHA384",
- "SHA512",
- };
-
- private static HashAlgorithm CreateAlgorithm(string algorithmName)
- {
- if (string.Equals(algorithmName, "SHA256", StringComparison.OrdinalIgnoreCase))
- {
- return SHA256.Create();
- }
- else if (string.Equals(algorithmName, "SHA384", StringComparison.OrdinalIgnoreCase))
- {
- return SHA384.Create();
- }
- else if (string.Equals(algorithmName, "SHA512", StringComparison.OrdinalIgnoreCase))
- {
- return SHA512.Create();
- }
-
- throw new ArgumentOutOfRangeException();
- }
- }
-} \ No newline at end of file
diff --git a/src/Components/WebAssembly/Build/src/Tasks/BlazorILLink.cs b/src/Components/WebAssembly/Build/src/Tasks/BlazorILLink.cs
deleted file mode 100644
index 0244e9f0c2..0000000000
--- a/src/Components/WebAssembly/Build/src/Tasks/BlazorILLink.cs
+++ /dev/null
@@ -1,194 +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 System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build.Tasks
-{
- // Based on https://github.com/mono/linker/blob/3b329b9481e300bcf4fb88a2eebf8cb5ef8b323b/src/ILLink.Tasks/LinkTask.cs
- public class BlazorILLink : ToolTask
- {
- private const string DotNetHostPathEnvironmentName = "DOTNET_HOST_PATH";
-
- [Required]
- public string ILLinkPath { get; set; }
-
- [Required]
- public ITaskItem[] AssemblyPaths { get; set; }
-
- public ITaskItem[] ReferenceAssemblyPaths { get; set; }
-
- [Required]
- public ITaskItem[] RootAssemblyNames { get; set; }
-
- [Required]
- public ITaskItem OutputDirectory { get; set; }
-
- public ITaskItem[] RootDescriptorFiles { get; set; }
-
- public bool ClearInitLocals { get; set; }
-
- public string ClearInitLocalsAssemblies { get; set; }
-
- public string ExtraArgs { get; set; }
-
- public bool DumpDependencies { get; set; }
-
- private string _dotnetPath;
-
- private string DotNetPath
- {
- get
- {
- if (!string.IsNullOrEmpty(_dotnetPath))
- {
- return _dotnetPath;
- }
-
- _dotnetPath = Environment.GetEnvironmentVariable(DotNetHostPathEnvironmentName);
- if (string.IsNullOrEmpty(_dotnetPath))
- {
- throw new InvalidOperationException($"{DotNetHostPathEnvironmentName} is not set");
- }
-
- return _dotnetPath;
- }
- }
-
- protected override MessageImportance StandardErrorLoggingImportance => MessageImportance.High;
-
- protected override string ToolName => Path.GetFileName(DotNetPath);
-
- protected override string GenerateFullPathToTool() => DotNetPath;
-
- protected override string GenerateCommandLineCommands()
- {
- var args = new StringBuilder();
- args.Append(Quote(ILLinkPath));
- return args.ToString();
- }
-
- private static string Quote(string path)
- {
- return $"\"{path.TrimEnd('\\')}\"";
- }
-
- protected override string GenerateResponseFileCommands()
- {
- var args = new StringBuilder();
-
- if (RootDescriptorFiles != null)
- {
- foreach (var rootFile in RootDescriptorFiles)
- {
- args.Append("-x ").AppendLine(Quote(rootFile.ItemSpec));
- }
- }
-
- foreach (var assemblyItem in RootAssemblyNames)
- {
- args.Append("-a ").AppendLine(Quote(assemblyItem.ItemSpec));
- }
-
- var assemblyNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
- foreach (var assembly in AssemblyPaths)
- {
- var assemblyPath = assembly.ItemSpec;
- var assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
-
- // If there are multiple paths with the same assembly name, only use the first one.
- if (!assemblyNames.Add(assemblyName))
- {
- continue;
- }
-
- args.Append("-reference ")
- .AppendLine(Quote(assemblyPath));
-
- var action = assembly.GetMetadata("action");
- if ((action != null) && (action.Length > 0))
- {
- args.Append("-p ");
- args.Append(action);
- args.Append(" ").AppendLine(Quote(assemblyName));
- }
- }
-
- if (ReferenceAssemblyPaths != null)
- {
- foreach (var assembly in ReferenceAssemblyPaths)
- {
- var assemblyPath = assembly.ItemSpec;
- var assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
-
- // Don't process references for which we already have
- // implementation assemblies.
- if (assemblyNames.Contains(assemblyName))
- {
- continue;
- }
-
- args.Append("-reference ").AppendLine(Quote(assemblyPath));
-
- // Treat reference assemblies as "skip". Ideally we
- // would not even look at the IL, but only use them to
- // resolve surface area.
- args.Append("-p skip ").AppendLine(Quote(assemblyName));
- }
- }
-
- if (OutputDirectory != null)
- {
- args.Append("-out ").AppendLine(Quote(OutputDirectory.ItemSpec));
- }
-
- if (ClearInitLocals)
- {
- args.AppendLine("--enable-opt clearinitlocals");
- if ((ClearInitLocalsAssemblies != null) && (ClearInitLocalsAssemblies.Length > 0))
- {
- args.Append("-m ClearInitLocalsAssemblies ");
- args.AppendLine(ClearInitLocalsAssemblies);
- }
- }
-
- if (ExtraArgs != null)
- {
- args.AppendLine(ExtraArgs);
- }
-
- if (DumpDependencies)
- {
- args.AppendLine("--dump-dependencies");
- }
-
- return args.ToString();
- }
-
- protected override bool HandleTaskExecutionErrors()
- {
- // Show a slightly better error than the standard ToolTask message that says "dotnet" failed.
- Log.LogError($"ILLink failed with exit code {ExitCode}.");
- return false;
- }
-
- protected override void LogEventsFromTextOutput(string singleLine, MessageImportance messageImportance)
- {
- if (!string.IsNullOrEmpty(singleLine) && singleLine.StartsWith("Unhandled exception.", StringComparison.Ordinal))
- {
- // The Mono linker currently prints out an entire stack trace when the linker fails.
- // We want to show something actionable in the VS Error window.
- Log.LogError(singleLine);
- }
- else
- {
- base.LogEventsFromTextOutput(singleLine, messageImportance);
- }
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/src/Tasks/BrotliCompressBlazorApplicationFiles.cs b/src/Components/WebAssembly/Build/src/Tasks/BrotliCompressBlazorApplicationFiles.cs
deleted file mode 100644
index fc4a4e6ad9..0000000000
--- a/src/Components/WebAssembly/Build/src/Tasks/BrotliCompressBlazorApplicationFiles.cs
+++ /dev/null
@@ -1,52 +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 System;
-using System.IO;
-using System.Text;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- public class BrotliCompressBlazorApplicationFiles : ToolTask
- {
- private const string DotNetHostPathEnvironmentName = "DOTNET_HOST_PATH";
-
- [Required]
- public string ManifestPath { get; set; }
-
- [Required]
- public string BlazorBrotliPath { get; set; }
-
- private string _dotnetPath;
-
- private string DotNetPath
- {
- get
- {
- if (!string.IsNullOrEmpty(_dotnetPath))
- {
- return _dotnetPath;
- }
-
- _dotnetPath = Environment.GetEnvironmentVariable(DotNetHostPathEnvironmentName);
- if (string.IsNullOrEmpty(_dotnetPath))
- {
- throw new InvalidOperationException($"{DotNetHostPathEnvironmentName} is not set");
- }
-
- return _dotnetPath;
- }
- }
-
- protected override MessageImportance StandardErrorLoggingImportance => MessageImportance.High;
-
- protected override string ToolName => Path.GetFileName(DotNetPath);
-
- protected override string GenerateFullPathToTool() => DotNetPath;
-
- protected override string GenerateCommandLineCommands() =>
- $"\"{BlazorBrotliPath}\" \"{ManifestPath}\"";
- }
-}
diff --git a/src/Components/WebAssembly/Build/src/Tasks/GenerateBlazorBootJson.cs b/src/Components/WebAssembly/Build/src/Tasks/GenerateBlazorBootJson.cs
deleted file mode 100644
index d3f1de66a9..0000000000
--- a/src/Components/WebAssembly/Build/src/Tasks/GenerateBlazorBootJson.cs
+++ /dev/null
@@ -1,232 +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 System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Runtime.Serialization;
-using System.Runtime.Serialization.Json;
-using System.Text;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary<string, string>;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- public class GenerateBlazorBootJson : Task
- {
- [Required]
- public string AssemblyPath { get; set; }
-
- [Required]
- public ITaskItem[] Resources { get; set; }
-
- [Required]
- public bool DebugBuild { get; set; }
-
- [Required]
- public bool LinkerEnabled { get; set; }
-
- [Required]
- public bool CacheBootResources { get; set; }
-
- public ITaskItem[] ConfigurationFiles { get; set; }
-
- [Required]
- public string OutputPath { get; set; }
-
- public override bool Execute()
- {
- using var fileStream = File.Create(OutputPath);
- var entryAssemblyName = AssemblyName.GetAssemblyName(AssemblyPath).Name;
-
- try
- {
- WriteBootJson(fileStream, entryAssemblyName);
- }
- catch (Exception ex)
- {
- Log.LogErrorFromException(ex);
- }
-
- return !Log.HasLoggedErrors;
- }
-
- // Internal for tests
- internal void WriteBootJson(Stream output, string entryAssemblyName)
- {
- var result = new BootJsonData
- {
- entryAssembly = entryAssemblyName,
- cacheBootResources = CacheBootResources,
- debugBuild = DebugBuild,
- linkerEnabled = LinkerEnabled,
- resources = new ResourcesData(),
- config = new List<string>(),
- };
-
- // Build a two-level dictionary of the form:
- // - assembly:
- // - UriPath (e.g., "System.Text.Json.dll")
- // - ContentHash (e.g., "4548fa2e9cf52986")
- // - runtime:
- // - UriPath (e.g., "dotnet.js")
- // - ContentHash (e.g., "3448f339acf512448")
- if (Resources != null)
- {
- var resourceData = result.resources;
- foreach (var resource in Resources)
- {
- var resourceTypeMetadata = resource.GetMetadata("BootManifestResourceType");
- ResourceHashesByNameDictionary resourceList;
- switch (resourceTypeMetadata)
- {
- case "runtime":
- resourceList = resourceData.runtime;
- break;
- case "assembly":
- resourceList = resourceData.assembly;
- break;
- case "dynamicAssembly":
- resourceList = resourceData.dynamicAssembly;
- break;
- case "pdb":
- resourceData.pdb ??= new ResourceHashesByNameDictionary();
- resourceList = resourceData.pdb;
- break;
- case "satellite":
- if (resourceData.satelliteResources is null)
- {
- resourceData.satelliteResources = new Dictionary<string, ResourceHashesByNameDictionary>(StringComparer.OrdinalIgnoreCase);
- }
- var resourceCulture = resource.GetMetadata("Culture");
- if (resourceCulture is null)
- {
- Log.LogWarning("Satellite resource {0} does not specify required metadata 'Culture'.", resource);
- continue;
- }
-
- if (!resourceData.satelliteResources.TryGetValue(resourceCulture, out resourceList))
- {
- resourceList = new ResourceHashesByNameDictionary();
- resourceData.satelliteResources.Add(resourceCulture, resourceList);
- }
- break;
- default:
- throw new NotSupportedException($"Unsupported BootManifestResourceType metadata value: {resourceTypeMetadata}");
- }
-
- var resourceName = GetResourceName(resource);
- if (!resourceList.ContainsKey(resourceName))
- {
- resourceList.Add(resourceName, $"sha256-{resource.GetMetadata("Integrity")}");
- }
- }
- }
-
- if (ConfigurationFiles != null)
- {
- foreach (var configFile in ConfigurationFiles)
- {
- result.config.Add(Path.GetFileName(configFile.ItemSpec));
- }
- }
-
- var serializer = new DataContractJsonSerializer(typeof(BootJsonData), new DataContractJsonSerializerSettings
- {
- UseSimpleDictionaryFormat = true
- });
-
- using var writer = JsonReaderWriterFactory.CreateJsonWriter(output, Encoding.UTF8, ownsStream: false, indent: true);
- serializer.WriteObject(writer, result);
- }
-
- private static string GetResourceName(ITaskItem item)
- {
- var name = item.GetMetadata("BootManifestResourceName");
-
- if (string.IsNullOrEmpty(name))
- {
- throw new Exception($"No BootManifestResourceName was specified for item '{item.ItemSpec}'");
- }
-
- return name.Replace('\\', '/');
- }
-
-#pragma warning disable IDE1006 // Naming Styles
- /// <summary>
- /// Defines the structure of a Blazor boot JSON file
- /// </summary>
- public class BootJsonData
- {
- /// <summary>
- /// Gets the name of the assembly with the application entry point
- /// </summary>
- public string entryAssembly { get; set; }
-
- /// <summary>
- /// Gets the set of resources needed to boot the application. This includes the transitive
- /// closure of .NET assemblies (including the entrypoint assembly), the dotnet.wasm file,
- /// and any PDBs to be loaded.
- ///
- /// Within <see cref="ResourceHashesByNameDictionary"/>, dictionary keys are resource names,
- /// and values are SHA-256 hashes formatted in prefixed base-64 style (e.g., 'sha256-abcdefg...')
- /// as used for subresource integrity checking.
- /// </summary>
- public ResourcesData resources { get; set; } = new ResourcesData();
-
- /// <summary>
- /// Gets a value that determines whether to enable caching of the <see cref="resources"/>
- /// inside a CacheStorage instance within the browser.
- /// </summary>
- public bool cacheBootResources { get; set; }
-
- /// <summary>
- /// Gets a value that determines if this is a debug build.
- /// </summary>
- public bool debugBuild { get; set; }
-
- /// <summary>
- /// Gets a value that determines if the linker is enabled.
- /// </summary>
- public bool linkerEnabled { get; set; }
-
- /// <summary>
- /// Config files for the application
- /// </summary>
- public List<string> config { get; set; }
- }
-
- public class ResourcesData
- {
- /// <summary>
- /// .NET Wasm runtime resources (dotnet.wasm, dotnet.js) etc.
- /// </summary>
- public ResourceHashesByNameDictionary runtime { get; set; } = new ResourceHashesByNameDictionary();
-
- /// <summary>
- /// "assembly" (.dll) resources
- /// </summary>
- public ResourceHashesByNameDictionary assembly { get; set; } = new ResourceHashesByNameDictionary();
-
- /// <summary>
- /// Assembly (.dll) resources that are loaded dynamically during runtime
- /// </summary>
- public ResourceHashesByNameDictionary dynamicAssembly { get; set; } = new ResourceHashesByNameDictionary();
-
- /// <summary>
- /// "debug" (.pdb) resources
- /// </summary>
- [DataMember(EmitDefaultValue = false)]
- public ResourceHashesByNameDictionary pdb { get; set; }
-
- /// <summary>
- /// localization (.satellite resx) resources
- /// </summary>
- [DataMember(EmitDefaultValue = false)]
- public Dictionary<string, ResourceHashesByNameDictionary> satelliteResources { get; set; }
- }
-#pragma warning restore IDE1006 // Naming Styles
- }
-} \ No newline at end of file
diff --git a/src/Components/WebAssembly/Build/src/Tasks/GenerateBlazorCompressionManifest.cs b/src/Components/WebAssembly/Build/src/Tasks/GenerateBlazorCompressionManifest.cs
deleted file mode 100644
index e7a7b16ee2..0000000000
--- a/src/Components/WebAssembly/Build/src/Tasks/GenerateBlazorCompressionManifest.cs
+++ /dev/null
@@ -1,102 +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 System;
-using System.Collections.Generic;
-using System.IO;
-using System.Runtime.Serialization;
-using System.Runtime.Serialization.Json;
-using System.Text;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- public class GenerateBlazorCompressionManifest : Task
- {
- [Required]
- public ITaskItem[] FilesToCompress { get; set; }
-
- [Required]
- public string ManifestPath { get; set; }
-
- public override bool Execute()
- {
- try
- {
- WriteCompressionManifest();
- }
- catch (Exception ex)
- {
- Log.LogErrorFromException(ex);
- }
-
- return !Log.HasLoggedErrors;
- }
-
- private void WriteCompressionManifest()
- {
- var tempFilePath = Path.GetTempFileName();
-
- var manifest = new ManifestData();
- var filesToCompress = new List<CompressedFile>();
-
- foreach (var file in FilesToCompress)
- {
- filesToCompress.Add(new CompressedFile
- {
- Source = file.GetMetadata("FullPath"),
- InputSource = file.GetMetadata("InputSource"),
- Target = file.GetMetadata("TargetCompressionPath"),
- });
- }
-
- manifest.FilesToCompress = filesToCompress.ToArray();
-
- var serializer = new DataContractJsonSerializer(typeof(ManifestData));
-
- using (var tempFile = File.OpenWrite(tempFilePath))
- {
- using (var writer = JsonReaderWriterFactory.CreateJsonWriter(tempFile, Encoding.UTF8, ownsStream: false, indent: true))
- {
- serializer.WriteObject(writer, manifest);
- }
- }
-
- if (!File.Exists(ManifestPath))
- {
- File.Move(tempFilePath, ManifestPath);
- return;
- }
-
- var originalText = File.ReadAllText(ManifestPath);
- var newManifest = File.ReadAllText(tempFilePath);
- if (!string.Equals(originalText, newManifest, StringComparison.Ordinal))
- {
- // OnlyWriteWhenDifferent
- File.Delete(ManifestPath);
- File.Move(tempFilePath, ManifestPath);
- }
- }
-
- [DataContract]
- private class ManifestData
- {
- [DataMember]
- public CompressedFile[] FilesToCompress { get; set; }
- }
-
- [DataContract]
- private class CompressedFile
- {
- [DataMember]
- public string Source { get; set; }
-
- [DataMember]
- public string InputSource { get; set; }
-
- [DataMember]
- public string Target { get; set; }
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/src/Tasks/GenerateServiceWorkerAssetsManifest.cs b/src/Components/WebAssembly/Build/src/Tasks/GenerateServiceWorkerAssetsManifest.cs
deleted file mode 100644
index 9a1885ad0c..0000000000
--- a/src/Components/WebAssembly/Build/src/Tasks/GenerateServiceWorkerAssetsManifest.cs
+++ /dev/null
@@ -1,82 +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 System.IO;
-using System.Linq;
-using System.Runtime.Serialization.Json;
-using System.Text;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-
-namespace Microsoft.AspNetCore.Blazor.Build
-{
- public class GenerateServiceWorkerAssetsManifest : Task
- {
- [Required]
- public string Version { get; set; }
-
- [Required]
- public ITaskItem[] AssetsWithHashes { get; set; }
-
- [Required]
- public string OutputPath { get; set; }
-
- public override bool Execute()
- {
- using var fileStream = File.Create(OutputPath);
- WriteFile(fileStream);
- return true;
- }
-
- internal void WriteFile(Stream stream)
- {
- var data = new AssetsManifestFile
- {
- version = Version,
- assets = AssetsWithHashes.Select(item => new AssetsManifestFileEntry
- {
- url = item.GetMetadata("AssetUrl"),
- hash = $"sha256-{item.GetMetadata("Integrity")}",
- }).ToArray()
- };
-
- using var streamWriter = new StreamWriter(stream, Encoding.UTF8, bufferSize: 50, leaveOpen: true);
- streamWriter.Write("self.assetsManifest = ");
- streamWriter.Flush();
-
- using var jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, ownsStream: false, indent: true);
- new DataContractJsonSerializer(typeof(AssetsManifestFile)).WriteObject(jsonWriter, data);
- jsonWriter.Flush();
-
- streamWriter.WriteLine(";");
- }
-
-#pragma warning disable IDE1006 // Naming Styles
- public class AssetsManifestFile
- {
- /// <summary>
- /// Gets or sets a version string.
- /// </summary>
- public string version { get; set; }
-
- /// <summary>
- /// Gets or sets the assets. Keys are URLs; values are base-64-formatted SHA256 content hashes.
- /// </summary>
- public AssetsManifestFileEntry[] assets { get; set; }
- }
-
- public class AssetsManifestFileEntry
- {
- /// <summary>
- /// Gets or sets the asset URL. Normally this will be relative to the application's base href.
- /// </summary>
- public string url { get; set; }
-
- /// <summary>
- /// Gets or sets the file content hash. This should be the base-64-formatted SHA256 value.
- /// </summary>
- public string hash { get; set; }
- }
-#pragma warning restore IDE1006 // Naming Styles
- }
-}
diff --git a/src/Components/WebAssembly/Build/src/Tasks/GenerateTypeGranularityLinkingConfig.cs b/src/Components/WebAssembly/Build/src/Tasks/GenerateTypeGranularityLinkingConfig.cs
deleted file mode 100644
index 66e673501e..0000000000
--- a/src/Components/WebAssembly/Build/src/Tasks/GenerateTypeGranularityLinkingConfig.cs
+++ /dev/null
@@ -1,48 +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 System.IO;
-using System.Xml.Linq;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build.Tasks
-{
- public class GenerateTypeGranularityLinkingConfig : Task
- {
- [Required]
- public ITaskItem[] Assemblies { get; set; }
-
- [Required]
- public string OutputPath { get; set; }
-
- public override bool Execute()
- {
- var linkerElement = new XElement("linker",
- new XComment(" THIS IS A GENERATED FILE - DO NOT EDIT MANUALLY "));
-
- foreach (var assembly in Assemblies)
- {
- var assemblyElement = CreateTypeGranularityConfig(assembly);
- linkerElement.Add(assemblyElement);
- }
-
- using var fileStream = File.Open(OutputPath, FileMode.Create);
- new XDocument(linkerElement).Save(fileStream);
-
- return true;
- }
-
- private XElement CreateTypeGranularityConfig(ITaskItem assembly)
- {
- // We match all types in the assembly, and for each one, tell the linker to preserve all
- // its members (preserve=all) but only if there's some reference to the type (required=false)
- return new XElement("assembly",
- new XAttribute("fullname", Path.GetFileNameWithoutExtension(assembly.ItemSpec)),
- new XElement("type",
- new XAttribute("fullname", "*"),
- new XAttribute("preserve", "all"),
- new XAttribute("required", "false")));
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/src/Tasks/GzipCompressBlazorApplicationFiles.cs b/src/Components/WebAssembly/Build/src/Tasks/GzipCompressBlazorApplicationFiles.cs
deleted file mode 100644
index 53d26328a3..0000000000
--- a/src/Components/WebAssembly/Build/src/Tasks/GzipCompressBlazorApplicationFiles.cs
+++ /dev/null
@@ -1,89 +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 System;
-using System.IO;
-using System.IO.Compression;
-using System.Runtime.Serialization;
-using System.Runtime.Serialization.Json;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- public class GzipCompressBlazorApplicationFiles : Task
- {
- [Required]
- public string ManifestPath { get; set; }
-
- public override bool Execute()
- {
- var serializer = new DataContractJsonSerializer(typeof(ManifestData));
-
- ManifestData manifest = null;
- using (var tempFile = File.OpenRead(ManifestPath))
- {
- manifest = (ManifestData)serializer.ReadObject(tempFile);
- }
-
- System.Threading.Tasks.Parallel.ForEach(manifest.FilesToCompress, (file) =>
- {
- var inputPath = file.Source;
- var inputSource = file.InputSource;
- var targetCompressionPath = file.Target;
-
- if (!File.Exists(inputSource))
- {
- Log.LogMessage($"Skipping '{inputPath}' because '{inputSource}' does not exist.");
- return;
- }
-
- if (File.Exists(targetCompressionPath) && File.GetLastWriteTimeUtc(inputSource) < File.GetLastWriteTimeUtc(targetCompressionPath))
- {
- // Incrementalism. If input source doesn't exist or it exists and is not newer than the expected output, do nothing.
- Log.LogMessage($"Skipping '{inputPath}' because '{targetCompressionPath}' is newer than '{inputSource}'.");
- return;
- }
-
- try
- {
- Directory.CreateDirectory(Path.GetDirectoryName(targetCompressionPath));
-
- using var sourceStream = File.OpenRead(inputPath);
- using var fileStream = new FileStream(targetCompressionPath, FileMode.Create);
- using var stream = new GZipStream(fileStream, CompressionLevel.Optimal);
-
- sourceStream.CopyTo(stream);
- }
- catch (Exception e)
- {
- Log.LogErrorFromException(e);
- throw;
- }
- });
-
- return !Log.HasLoggedErrors;
- }
-
- [DataContract]
- private class ManifestData
- {
- [DataMember]
- public CompressedFile[] FilesToCompress { get; set; }
- }
-
- [DataContract]
- private class CompressedFile
- {
- [DataMember]
- public string Source { get; set; }
-
- [DataMember]
- public string InputSource { get; set; }
-
- [DataMember]
- public string Target { get; set; }
- }
- }
-}
-
diff --git a/src/Components/WebAssembly/Build/src/Tasks/ResolveBlazorRuntimeDependencies.cs b/src/Components/WebAssembly/Build/src/Tasks/ResolveBlazorRuntimeDependencies.cs
deleted file mode 100644
index 4598432a1c..0000000000
--- a/src/Components/WebAssembly/Build/src/Tasks/ResolveBlazorRuntimeDependencies.cs
+++ /dev/null
@@ -1,203 +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 System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Reflection.Metadata;
-using System.Reflection.PortableExecutable;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- public class ResolveBlazorRuntimeDependencies : Task
- {
- [Required]
- public string EntryPoint { get; set; }
-
- [Required]
- public ITaskItem[] ApplicationDependencies { get; set; }
-
- [Required]
- public ITaskItem[] WebAssemblyBCLAssemblies { get; set; }
-
- [Output]
- public ITaskItem[] Dependencies { get; set; }
-
- public override bool Execute()
- {
- var paths = ResolveRuntimeDependenciesCore(EntryPoint, ApplicationDependencies.Select(c => c.ItemSpec), WebAssemblyBCLAssemblies.Select(c => c.ItemSpec));
- Dependencies = paths.Select(p => new TaskItem(p)).ToArray();
-
- return true;
- }
-
- public static IEnumerable<string> ResolveRuntimeDependenciesCore(
- string entryPoint,
- IEnumerable<string> applicationDependencies,
- IEnumerable<string> monoBclAssemblies)
- {
- var entryAssembly = new AssemblyEntry(entryPoint, GetAssemblyName(entryPoint));
-
- var dependencies = CreateAssemblyLookup(applicationDependencies);
-
- var bcl = CreateAssemblyLookup(monoBclAssemblies);
-
- var assemblyResolutionContext = new AssemblyResolutionContext(
- entryAssembly,
- dependencies,
- bcl);
-
- assemblyResolutionContext.ResolveAssemblies();
-
- var paths = assemblyResolutionContext.Results.Select(r => r.Path);
- return paths.Concat(FindPdbs(paths));
-
- static Dictionary<string, AssemblyEntry> CreateAssemblyLookup(IEnumerable<string> assemblyPaths)
- {
- var dictionary = new Dictionary<string, AssemblyEntry>(StringComparer.Ordinal);
- foreach (var path in assemblyPaths)
- {
- var assemblyName = AssemblyName.GetAssemblyName(path).Name;
- if (dictionary.TryGetValue(assemblyName, out var previous))
- {
- throw new InvalidOperationException($"Multiple assemblies found with the same assembly name '{assemblyName}':" +
- Environment.NewLine + string.Join(Environment.NewLine, previous, path));
- }
- dictionary[assemblyName] = new AssemblyEntry(path, assemblyName);
- }
-
- return dictionary;
- }
- }
-
- private static string GetAssemblyName(string assemblyPath)
- {
- return AssemblyName.GetAssemblyName(assemblyPath).Name;
- }
-
- private static IEnumerable<string> FindPdbs(IEnumerable<string> dllPaths)
- {
- return dllPaths
- .Select(path => Path.ChangeExtension(path, "pdb"))
- .Where(path => File.Exists(path));
- }
-
- public class AssemblyResolutionContext
- {
- public AssemblyResolutionContext(
- AssemblyEntry entryAssembly,
- Dictionary<string, AssemblyEntry> dependencies,
- Dictionary<string, AssemblyEntry> bcl)
- {
- EntryAssembly = entryAssembly;
- Dependencies = dependencies;
- Bcl = bcl;
- }
-
- public AssemblyEntry EntryAssembly { get; }
- public Dictionary<string, AssemblyEntry> Dependencies { get; }
- public Dictionary<string, AssemblyEntry> Bcl { get; }
-
- public IList<AssemblyEntry> Results { get; } = new List<AssemblyEntry>();
-
- internal void ResolveAssemblies()
- {
- var visitedAssemblies = new HashSet<string>();
- var pendingAssemblies = new Stack<string>();
- pendingAssemblies.Push(EntryAssembly.Name);
- ResolveAssembliesCore();
-
- void ResolveAssembliesCore()
- {
- while (pendingAssemblies.Count > 0)
- {
- var current = pendingAssemblies.Pop();
- if (visitedAssemblies.Add(current))
- {
- // Not all references will be resolvable within the Mono BCL.
- // Skipping unresolved assemblies here is equivalent to passing "--skip-unresolved true" to the Mono linker.
- if (Resolve(current) is AssemblyEntry resolved)
- {
- Results.Add(resolved);
- var references = GetAssemblyReferences(resolved.Path);
- foreach (var reference in references)
- {
- pendingAssemblies.Push(reference);
- }
- }
- }
- }
- }
-
- AssemblyEntry? Resolve(string assemblyName)
- {
- if (EntryAssembly.Name == assemblyName)
- {
- return EntryAssembly;
- }
-
- // Resolution logic. For right now, we will prefer the mono BCL version of a given
- // assembly if there is a candidate assembly and an equivalent mono assembly.
- if (Bcl.TryGetValue(assemblyName, out var assembly) ||
- Dependencies.TryGetValue(assemblyName, out assembly))
- {
- return assembly;
- }
-
- return null;
- }
-
- static IReadOnlyList<string> GetAssemblyReferences(string assemblyPath)
- {
- try
- {
- using var peReader = new PEReader(File.OpenRead(assemblyPath));
- if (!peReader.HasMetadata)
- {
- return Array.Empty<string>(); // not a managed assembly
- }
-
- var metadataReader = peReader.GetMetadataReader();
-
- var references = new List<string>();
- foreach (var handle in metadataReader.AssemblyReferences)
- {
- var reference = metadataReader.GetAssemblyReference(handle);
- var referenceName = metadataReader.GetString(reference.Name);
-
- references.Add(referenceName);
- }
-
- return references;
- }
- catch (BadImageFormatException)
- {
- // not a PE file, or invalid metadata
- }
-
- return Array.Empty<string>(); // not a managed assembly
- }
- }
- }
-
- [DebuggerDisplay("{ToString(),nq}")]
- public readonly struct AssemblyEntry
- {
- public AssemblyEntry(string path, string name)
- {
- Path = path;
- Name = name;
- }
-
- public string Path { get; }
- public string Name { get; }
-
- public override string ToString() => Name;
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/src/build/netstandard1.0/Microsoft.AspNetCore.Components.WebAssembly.Build.props b/src/Components/WebAssembly/Build/src/build/netstandard1.0/Microsoft.AspNetCore.Components.WebAssembly.Build.props
deleted file mode 100644
index a85c05ce87..0000000000
--- a/src/Components/WebAssembly/Build/src/build/netstandard1.0/Microsoft.AspNetCore.Components.WebAssembly.Build.props
+++ /dev/null
@@ -1,7 +0,0 @@
-<Project>
- <Import Project="$(MSBuildThisFileDirectory)..\..\targets\All.props" />
-
- <PropertyGroup>
- <ReferencesComponentsWebAssemblyBuild>true</ReferencesComponentsWebAssemblyBuild>
- </PropertyGroup>
-</Project>
diff --git a/src/Components/WebAssembly/Build/src/build/netstandard1.0/Microsoft.AspNetCore.Components.WebAssembly.Build.targets b/src/Components/WebAssembly/Build/src/build/netstandard1.0/Microsoft.AspNetCore.Components.WebAssembly.Build.targets
deleted file mode 100644
index 35115b33b3..0000000000
--- a/src/Components/WebAssembly/Build/src/build/netstandard1.0/Microsoft.AspNetCore.Components.WebAssembly.Build.targets
+++ /dev/null
@@ -1,3 +0,0 @@
-<Project>
- <Import Project="$(MSBuildThisFileDirectory)..\..\targets\All.targets" />
-</Project>
diff --git a/src/Components/WebAssembly/Build/src/targets/All.props b/src/Components/WebAssembly/Build/src/targets/All.props
deleted file mode 100644
index 8315d3cb40..0000000000
--- a/src/Components/WebAssembly/Build/src/targets/All.props
+++ /dev/null
@@ -1,16 +0,0 @@
-<Project>
- <Import Project="Blazor.MonoRuntime.props" />
-
- <Import Project="StaticWebAssets.props" />
-
- <PropertyGroup>
-
- <!-- Assets for a Blazor app are exposed on the root folder by default. -->
- <StaticWebAssetBasePath>/</StaticWebAssetBasePath>
-
- <!-- When using IISExpress with a standalone app, there's no point restarting IISExpress after build. It slows things unnecessarily and breaks in-flight HTTP requests. -->
- <NoRestartServerOnBuild>true</NoRestartServerOnBuild>
-
- <BlazorEnableCompression Condition="'$(BlazorEnableCompression)' == ''">true</BlazorEnableCompression>
- </PropertyGroup>
-</Project>
diff --git a/src/Components/WebAssembly/Build/src/targets/All.targets b/src/Components/WebAssembly/Build/src/targets/All.targets
deleted file mode 100644
index 5966cec27f..0000000000
--- a/src/Components/WebAssembly/Build/src/targets/All.targets
+++ /dev/null
@@ -1,21 +0,0 @@
-<Project>
- <PropertyGroup>
- <_BlazorToolsDir Condition="'$(_BlazorToolsDir)' == ''">$(MSBuildThisFileDirectory)..\tools\</_BlazorToolsDir>
- <_BlazorTasksTFM Condition=" '$(MSBuildRuntimeType)' == 'Core'">netcoreapp</_BlazorTasksTFM>
- <_BlazorTasksTFM Condition=" '$(_BlazorTasksTFM)' == ''">netfx</_BlazorTasksTFM>
- <_BlazorTasksPath>$(_BlazorToolsDir)$(_BlazorTasksTFM)\Microsoft.AspNetCore.Components.WebAssembly.Build.Tasks.dll</_BlazorTasksPath>
-
- <!-- The Blazor build code can only find your referenced assemblies if they are in the output directory -->
- <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
-
- <!-- By default, enable debugging for debug builds. -->
- <BlazorEnableDebugging Condition="'$(Configuration)' == 'Debug' AND '$(BlazorEnableDebugging)' == ''">true</BlazorEnableDebugging>
- </PropertyGroup>
-
- <Import Project="Blazor.MonoRuntime.targets" />
- <Import Project="Publish.targets" />
- <Import Project="StaticWebAssets.targets" />
- <Import Project="ServiceWorkerAssetsManifest.targets" />
- <Import Project="Compression.targets" Condition="'$(BlazorEnableCompression)' == 'true'" />
-
-</Project>
diff --git a/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.props b/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.props
deleted file mode 100644
index 453deddacd..0000000000
--- a/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.props
+++ /dev/null
@@ -1,20 +0,0 @@
-<Project>
-
- <PropertyGroup>
- <BlazorWebAssemblyI18NAssemblies>none</BlazorWebAssemblyI18NAssemblies> <!-- See Mono linker docs - allows comma-separated values from: none,all,cjk,mideast,other,rare,west -->
- <AdditionalMonoLinkerOptions>--disable-opt unreachablebodies --verbose --strip-security true --exclude-feature com -v false -c link -u link -b true</AdditionalMonoLinkerOptions>
-
- <_BlazorJsPath Condition="'$(_BlazorJsPath)' == ''">$(MSBuildThisFileDirectory)..\tools\blazor\blazor.webassembly.js</_BlazorJsPath>
- <_BaseBlazorRuntimeOutputPath>_framework\</_BaseBlazorRuntimeOutputPath>
- <_BlazorRuntimeBinOutputPath>$(_BaseBlazorRuntimeOutputPath)_bin\</_BlazorRuntimeBinOutputPath>
- <_BlazorRuntimeWasmOutputPath>$(_BaseBlazorRuntimeOutputPath)wasm\</_BlazorRuntimeWasmOutputPath>
- <_BlazorBuiltInBclLinkerDescriptor>$(MSBuildThisFileDirectory)BuiltInBclLinkerDescriptor.xml</_BlazorBuiltInBclLinkerDescriptor>
- <_BlazorCollationLinkerDescriptor>$(MSBuildThisFileDirectory)CollationLinkerDescriptor.xml</_BlazorCollationLinkerDescriptor>
- <_BlazorBootJsonName>blazor.boot.json</_BlazorBootJsonName>
- </PropertyGroup>
-
- <ItemGroup>
- <BlazorLinkerDescriptor Include="$(_BlazorBuiltInBclLinkerDescriptor)" />
- </ItemGroup>
-
-</Project>
diff --git a/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets b/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets
deleted file mode 100644
index c143445685..0000000000
--- a/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets
+++ /dev/null
@@ -1,489 +0,0 @@
-<Project>
- <UsingTask TaskName="BlazorGetFileHash" AssemblyFile="$(_BlazorTasksPath)" />
-
- <PropertyGroup>
- <BlazorWebAssemblyEnableLinking Condition="'$(BlazorWebAssemblyEnableLinking)' == '' AND '$(Configuration)' != 'Debug'">true</BlazorWebAssemblyEnableLinking>
- <BlazorWebAssemblyEnableLinking Condition="'$(BlazorWebAssemblyEnableLinking)' == ''">false</BlazorWebAssemblyEnableLinking>
- </PropertyGroup>
-
- <Target
- Name="_PrepareBlazorOutputs"
- DependsOnTargets="_ResolveBlazorInputs;_ResolveBlazorOutputs;_GenerateBlazorBootJson;_GenerateBlazorBootJsonIntegrity">
- </Target>
-
- <Target Name="_ResolveBlazorInputs" DependsOnTargets="ResolveReferences;ResolveRuntimePackAssets">
- <Error Text="BlazorLinkOnBuild has been renamed to BlazorWebAssemblyEnableLinking. Please update your project files to use the new property."
- Condition="'$(BlazorLinkOnBuild)' != ''" />
-
- <PropertyGroup>
- <!-- /obj/<<configuration>>/<<targetframework>>/blazor -->
- <_BlazorIntermediateOutputPath>$(IntermediateOutputPath)blazor\</_BlazorIntermediateOutputPath>
-
- <!-- /obj/<<configuration>>/<<targetframework>>/blazor/linker.descriptor.xml -->
- <_GeneratedBlazorLinkerDescriptor>$(_BlazorIntermediateOutputPath)linker.descriptor.xml</_GeneratedBlazorLinkerDescriptor>
-
- <_TypeGranularityLinkerDescriptor>$(_BlazorIntermediateOutputPath)linker.typegranularityconfig.xml</_TypeGranularityLinkerDescriptor>
-
- <!-- /obj/<<configuration>>/<<targetframework>>/blazor/linker/ -->
- <_BlazorIntermediateLinkerOutputPath>$(_BlazorIntermediateOutputPath)linker/</_BlazorIntermediateLinkerOutputPath>
-
- <!-- /obj/<<configuration>>/<<targetframework>>/blazor/blazor.boot.json -->
- <_BlazorBootJsonIntermediateOutputPath>$(_BlazorIntermediateOutputPath)$(_BlazorBootJsonName)</_BlazorBootJsonIntermediateOutputPath>
-
- <_BlazorLinkerOutputCache>$(_BlazorIntermediateOutputPath)linker.output</_BlazorLinkerOutputCache>
-
- <_BlazorApplicationAssembliesCacheFile>$(_BlazorIntermediateOutputPath)unlinked.output</_BlazorApplicationAssembliesCacheFile>
- </PropertyGroup>
-
- <!--
- When running from Desktop MSBuild, DOTNET_HOST_PATH is not set.
- In this case, explicitly specify the path to the dotnet host.
- -->
- <PropertyGroup Condition=" '$(DOTNET_HOST_PATH)' == '' ">
- <_DotNetHostDirectory>$(NetCoreRoot)</_DotNetHostDirectory>
- <_DotNetHostFileName>dotnet</_DotNetHostFileName>
- <_DotNetHostFileName Condition=" '$(OS)' == 'Windows_NT' ">dotnet.exe</_DotNetHostFileName>
- </PropertyGroup>
-
- <ItemGroup>
- <_WebAssemblyBCLFolder Include="
- $(ComponentsWebAssemblyBaseClassLibraryPath);
- $(ComponentsWebAssemblyBaseClassLibraryFacadesPath);
- $(ComponentsWebAssemblyFrameworkPath)" />
-
- <_WebAssemblyBCLAssembly Include="%(_WebAssemblyBCLFolder.Identity)*.dll" />
-
- <_BlazorConfigFile Include="wwwroot\appsettings*.json" />
- </ItemGroup>
-
- <!--
- Calculate the assemblies that act as inputs to calculate assembly closure. Based on _ComputeAssembliesToPostprocessOnPublish which is used as input to SDK's linker
- https://github.com/dotnet/sdk/blob/d597e7b09d7657ba4e326d6734e14fcbf8473564/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets#L864-L873
- -->
- <ItemGroup>
- <!-- Assemblies from packages -->
- <_BlazorManagedRuntimeAssembly Include="@(RuntimeCopyLocalItems)" />
-
- <!-- Assemblies from other references -->
- <_BlazorUserRuntimeAssembly Include="@(ReferencePath->WithMetadataValue('CopyLocal', 'true'))" />
- <_BlazorUserRuntimeAssembly Include="@(ReferenceDependencyPaths->WithMetadataValue('CopyLocal', 'true'))" />
-
- <_BlazorManagedRuntimeAssembly Include="@(_BlazorUserRuntimeAssembly)" />
- <_BlazorManagedRuntimeAssembly Include="@(IntermediateAssembly)" />
- </ItemGroup>
-
- <MakeDir Directories="$(_BlazorIntermediateOutputPath)" />
- </Target>
-
- <UsingTask TaskName="BlazorWriteSatelliteAssemblyFile" AssemblyFile="$(_BlazorTasksPath)" />
- <UsingTask TaskName="BlazorReadSatelliteAssemblyFile" AssemblyFile="$(_BlazorTasksPath)" />
-
- <Target Name="_ResolveBlazorOutputs" DependsOnTargets="_ResolveBlazorOutputsWhenLinked;_ResolveBlazorOutputsWhenNotLinked">
- <!--
- These are the items calculated as the closure of the runtime assemblies, either by calling the linker
- or by calling our custom ResolveBlazorRuntimeDependencies task if the linker was disabled. Other than
- satellite assemblies, this should include all assemblies needed to run the application.
- -->
- <ItemGroup>
- <_BlazorJSFile Include="$(_BlazorJSPath)" />
- <_BlazorJSFile Include="$(_BlazorJSMapPath)" Condition="Exists('$(_BlazorJSMapPath)')" />
-
- <_DotNetWasmRuntimeFile Include="$(ComponentsWebAssemblyRuntimePath)*"/>
- <_DotNetWasmRuntimeFile
- Remove="%(Identity)"
- Condition="'$(BlazorEnableTimeZoneSupport)' == 'false' AND '%(FileName)%(Extension)' == 'dotnet.timezones.dat'" />
-
- <!--
- ReferenceCopyLocalPaths includes all files that are part of the build out with CopyLocalLockFileAssemblies on.
- Remove assemblies that are inputs to calculating the assembly closure. Instead use the resolved outputs, since it is the minimal set.
-
- ReferenceCopyLocalPaths also includes satellite assemblies from referenced projects but are inexpicably missing
- any metadata that might allow them to be differentiated. We'll explicitly add those
- to _BlazorOutputWithTargetPath so that satellite assemblies from packages, the current project and referenced project
- are all treated the same.
- -->
- <_BlazorCopyLocalPaths Include="@(ReferenceCopyLocalPaths)"
- Exclude="@(_BlazorManagedRuntimeAssembly);@(ReferenceSatellitePaths)"
- Condition="'%(Extension)' == '.dll'" />
-
- <_BlazorCopyLocalPaths Include="@(IntermediateSatelliteAssembliesWithTargetPath)">
- <DestinationSubDirectory>%(IntermediateSatelliteAssembliesWithTargetPath.Culture)\</DestinationSubDirectory>
- </_BlazorCopyLocalPaths>
-
- <_BlazorOutputWithTargetPath Include="@(_BlazorCopyLocalPaths)">
- <!-- This group is for satellite assemblies. We set the resource name to include a path, e.g. "fr\\SomeAssembly.resources.dll" -->
- <BootManifestResourceType Condition="'%(_BlazorCopyLocalPaths.Extension)' == '.pdb'">pdb</BootManifestResourceType>
- <BootManifestResourceType Condition="'%(_BlazorCopyLocalPaths.Culture)' == '' AND '%(_BlazorCopyLocalPaths.Extension)' == '.dll'">assembly</BootManifestResourceType>
- <BootManifestResourceType Condition="'%(_BlazorCopyLocalPaths.Culture)' != '' AND '%(_BlazorCopyLocalPaths.Extension)' == '.dll'">satellite</BootManifestResourceType>
- <BootManifestResourceName>%(_BlazorCopyLocalPaths.DestinationSubDirectory)%(FileName)%(Extension)</BootManifestResourceName>
- <TargetOutputPath>$(_BlazorRuntimeBinOutputPath)%(_BlazorCopyLocalPaths.DestinationSubDirectory)%(FileName)%(Extension)</TargetOutputPath>
- </_BlazorOutputWithTargetPath>
-
- <_BlazorOutputWithTargetPath Include="@(ReferenceSatellitePaths)">
- <Culture>$([System.String]::Copy('%(ReferenceSatellitePaths.DestinationSubDirectory)').Trim('\').Trim('/'))</Culture>
- <BootManifestResourceType>satellite</BootManifestResourceType>
- <BootManifestResourceName>%(ReferenceSatellitePaths.DestinationSubDirectory)%(FileName)%(Extension)</BootManifestResourceName>
- <TargetOutputPath>$(_BlazorRuntimeBinOutputPath)%(ReferenceSatellitePaths.DestinationSubDirectory)%(FileName)%(Extension)</TargetOutputPath>
- </_BlazorOutputWithTargetPath>
-
- <_BlazorOutputWithTargetPath Include="@(_BlazorResolvedAssembly)">
- <BootManifestResourceType Condition="'%(Extension)' == '.dll'">assembly</BootManifestResourceType>
- <BootManifestResourceType Condition="'%(Extension)' == '.pdb'">pdb</BootManifestResourceType>
- <BootManifestResourceType Condition="@(BlazorWebAssemblyLazyLoad->AnyHaveMetadataValue('Identity', '%(Filename)')) != ''">dynamicAssembly</BootManifestResourceType>
- <BootManifestResourceName>%(FileName)%(Extension)</BootManifestResourceName>
- <TargetOutputPath>$(_BlazorRuntimeBinOutputPath)%(FileName)%(Extension)</TargetOutputPath>
- </_BlazorOutputWithTargetPath>
-
- <_BlazorOutputWithTargetPath Include="@(_DotNetWasmRuntimeFile)">
- <TargetOutputPath>$(_BlazorRuntimeWasmOutputPath)%(FileName)%(Extension)</TargetOutputPath>
- <BootManifestResourceType>runtime</BootManifestResourceType>
- <BootManifestResourceName>%(FileName)%(Extension)</BootManifestResourceName>
- </_BlazorOutputWithTargetPath>
-
- <_BlazorOutputWithTargetPath Include="@(_BlazorJSFile)">
- <TargetOutputPath>$(_BaseBlazorRuntimeOutputPath)%(FileName)%(Extension)</TargetOutputPath>
- </_BlazorOutputWithTargetPath>
-
- <_BlazorWriteSatelliteAssembly Include="@(_BlazorOutputWithTargetPath->WithMetadataValue('BootManifestResourceType', 'satellite'))" />
- </ItemGroup>
-
- <!--
- When building with BuildingProject=false, satellite assemblies do not get resolved (the ones for the current project and the one for
- referenced project). BuildingProject=false is typically set for referenced projects when building inside VisualStudio.
- To workaround this, we'll stash metadata during a regular build, and rehydrate from it when BuildingProject=false.
- -->
-
- <PropertyGroup>
- <_BlazorSatelliteAssemblyStashFile>$(_BlazorIntermediateOutputPath)blazor.satelliteasm.props</_BlazorSatelliteAssemblyStashFile>
- </PropertyGroup>
-
- <BlazorWriteSatelliteAssemblyFile
- SatelliteAssembly="@(_BlazorWriteSatelliteAssembly)"
- WriteFile="$(_BlazorSatelliteAssemblyStashFile)"
- Condition="'$(BuildingProject)' == 'true' AND '@(_BlazorWriteSatelliteAssembly->Count())' != '0'" />
-
- <Delete
- Files="$(_BlazorSatelliteAssemblyStashFile)"
- Condition="'$(BuildingProject)' == 'true' AND '@(_BlazorWriteSatelliteAssembly->Count())' == '0' and EXISTS('$(_BlazorSatelliteAssemblyStashFile)')" />
-
- <BlazorReadSatelliteAssemblyFile
- ReadFile="$(_BlazorSatelliteAssemblyStashFile)"
- Condition="'$(BuildingProject)' != 'true' AND EXISTS('$(_BlazorSatelliteAssemblyStashFile)')">
- <Output TaskParameter="SatelliteAssembly" ItemName="_BlazorReadSatelliteAssembly" />
- </BlazorReadSatelliteAssemblyFile>
-
- <ItemGroup>
- <FileWrites Include="$(_BlazorSatelliteAssemblyStashFile)" Condition="Exists('$(_BlazorSatelliteAssemblyStashFile)')" />
- </ItemGroup>
-
- <ItemGroup Condition="'@(_BlazorReadSatelliteAssembly->Count())' != '0'">
- <!-- We've imported a previously stashed file. Let's turn in to a _BlazorOutputWithTargetPath -->
- <_BlazorOutputWithTargetPath Include="@(_BlazorReadSatelliteAssembly)">
- <BootManifestResourceType>satellite</BootManifestResourceType>
- <BootManifestResourceName>%(_BlazorReadSatelliteAssembly.DestinationSubDirectory)%(FileName)%(Extension)</BootManifestResourceName>
- <TargetOutputPath>$(_BlazorRuntimeBinOutputPath)%(_BlazorReadSatelliteAssembly.DestinationSubDirectory)%(FileName)%(Extension)</TargetOutputPath>
- </_BlazorOutputWithTargetPath>
- </ItemGroup>
-
- <!--
- We need to know at build time (not publish time) whether or not to include pdbs in the
- blazor.boot.json file, so this is controlled by the BlazorEnableDebugging flag, whose
- default value is determined by the build configuration.
- -->
- <ItemGroup Condition="'$(BlazorEnableDebugging)' != 'true'">
- <_BlazorOutputWithTargetPath Remove="@(_BlazorOutputWithTargetPath)" Condition="'%(Extension)' == '.pdb'" />
- </ItemGroup>
-
- <ItemGroup>
- <_ExistingBlazorOutputWithTargetPath Include="@(_BlazorOutputWithTargetPath)" Condition="Exists('%(FullPath)')" />
- </ItemGroup>
-
- <BlazorGetFileHash Files="@(_ExistingBlazorOutputWithTargetPath)" Algorithm="SHA256" HashEncoding="base64">
- <Output TaskParameter="Items" ItemName="_BlazorOutputWithHash" />
- </BlazorGetFileHash>
-
- <ItemGroup>
- <_BlazorOutputWithIntegrity Include="@(_BlazorOutputWithHash)">
- <Integrity>%(_BlazorOutputWithHash.FileHash)</Integrity>
- <IntegrityFile>$(IntermediateOutputPath)integrity\$([System.String]::Copy('%(FileHash)').Replace('/','-').Replace('+','_')).hash</IntegrityFile>
- </_BlazorOutputWithIntegrity>
-
- <_BlazorOutputWithTargetPath Remove="@(_BlazorOutputWithIntegrity)" />
- <_BlazorOutputWithTargetPath Include="@(_BlazorOutputWithIntegrity)" RemoveMetadata="FileHash;FileHashAlgorithm" />
-
- <MakeDir Directories="$(IntermediateOutputPath)integrity" />
- </ItemGroup>
-
- <WriteLinesToFile Lines="%(_BlazorOutputWithIntegrity.Integrity)" File="%(_BlazorOutputWithIntegrity.IntegrityFile)" WriteOnlyWhenDifferent="true" Overwrite="true" />
-
- <ItemGroup>
- <FileWrites Include="%(_BlazorOutputWithIntegrity.IntegrityFile)" />
- </ItemGroup>
-
- </Target>
-
- <!--
- Linker enabled part of the pipeline:
-
- * If there are no descriptors defined, generate a new linker descriptor.
- * Invoke the linker and write linked files to a well-known directory.
- * Collect the outputs of the linker.
- -->
-
- <Target
- Name="_ResolveBlazorOutputsWhenLinked"
- Condition="'$(BlazorWebAssemblyEnableLinking)' == 'true'"
- DependsOnTargets="_PrepareBlazorLinkerInputs;_GenerateBlazorLinkerDescriptor;_GenerateTypeGranularLinkerDescriptor;_LinkBlazorApplication">
-
- <!-- _BlazorLinkerOutputCache records files linked during the last incremental build of the target. Read the contents and assign linked files to be copied to the output. -->
- <ReadLinesFromFile File="$(_BlazorLinkerOutputCache)">
- <Output TaskParameter="Lines" ItemName="_BlazorResolvedAssembly"/>
- </ReadLinesFromFile>
- </Target>
-
- <Target Name="_PrepareBlazorLinkerInputs">
- <ItemGroup>
- <_BlazorRuntimeCopyLocalItems Include="@(RuntimeCopyLocalItems)" />
-
- <!--
- Any assembly from a package reference that starts with System. file name is allowed to be linked.
- Assemblies from Microsoft.AspNetCore and Microsoft.Extensions, are also linked but with TypeGranularity.
- -->
- <_BlazorRuntimeCopyLocalItems IsLinkable="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('System.'))" />
- <_BlazorRuntimeCopyLocalItems IsLinkable="true" TypeGranularity="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.'))" />
- <_BlazorRuntimeCopyLocalItems IsLinkable="true" TypeGranularity="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('Microsoft.Extensions.'))" />
-
- <_BlazorAssemblyToLink Include="@(_WebAssemblyBCLAssembly)" />
- <_BlazorAssemblyToLink Include="@(_BlazorRuntimeCopyLocalItems)" Condition="'%(_BlazorRuntimeCopyLocalItems.IsLinkable)' == 'true'" />
-
- <_BlazorLinkerRoot Include="@(IntermediateAssembly)" />
- <_BlazorLinkerRoot Include="@(_BlazorUserRuntimeAssembly)" />
- <_BlazorLinkerRoot Include="@(_BlazorRuntimeCopyLocalItems)" Condition="'%(_BlazorRuntimeCopyLocalItems.IsLinkable)' != 'true'" />
- </ItemGroup>
-
- <!-- When specifically requested, include the linker substitutions file that strips out collation information.-->
- <PropertyGroup Condition="'$(BlazorWebAssemblyPreserveCollationData)' == 'false'">
- <AdditionalMonoLinkerOptions>$(AdditionalMonoLinkerOptions) --substitutions "$(_BlazorCollationLinkerDescriptor)"</AdditionalMonoLinkerOptions>
- </PropertyGroup>
- </Target>
-
- <UsingTask TaskName="BlazorCreateRootDescriptorFile" AssemblyFile="$(_BlazorTasksPath)" />
- <Target Name="_GenerateBlazorLinkerDescriptor"
- Inputs="@(IntermediateAssembly)"
- Outputs="$(_GeneratedBlazorLinkerDescriptor)">
-
- <!-- Generate linker descriptors if the project doesn't explicitly provide one. -->
-
- <BlazorCreateRootDescriptorFile
- AssemblyNames="@(IntermediateAssembly->'%(Filename)')"
- RootDescriptorFilePath="$(_GeneratedBlazorLinkerDescriptor)" />
-
- <ItemGroup>
- <FileWrites Include="$(_GeneratedBlazorLinkerDescriptor)" />
- <BlazorLinkerDescriptor Include="$(_GeneratedBlazorLinkerDescriptor)" />
- </ItemGroup>
- </Target>
-
- <UsingTask TaskName="GenerateTypeGranularityLinkingConfig" AssemblyFile="$(_BlazorTasksPath)" />
- <Target Name="_GenerateTypeGranularLinkerDescriptor"
- Inputs="@(_BlazorAssemblyToLink->WithMetadataValue('TypeGranularity', 'true'))"
- Outputs="$(_TypeGranularityLinkerDescriptor)">
-
- <GenerateTypeGranularityLinkingConfig
- Assemblies="@(_BlazorAssemblyToLink->WithMetadataValue('TypeGranularity', 'true'))"
- OutputPath="$(_TypeGranularityLinkerDescriptor)" />
-
- <ItemGroup>
- <BlazorLinkerDescriptor Include="$(_TypeGranularityLinkerDescriptor)" />
- <FileWrites Include="$(_TypeGranularityLinkerDescriptor)" />
- </ItemGroup>
- </Target>
-
- <!--
- Note that the VS-specific condition below is a workaround for https://github.com/dotnet/aspnetcore/issues/19822
- For more details, see https://github.com/dotnet/aspnetcore/issues/20413
- -->
- <UsingTask TaskName="BlazorILLink" AssemblyFile="$(_BlazorTasksPath)" />
- <Target
- Name="_LinkBlazorApplication"
- Inputs="$(ProjectAssetsFile);
- @(_BlazorManagedRuntimeAssembly);
- @(BlazorLinkerDescriptor);
- $(MSBuildAllProjects)"
- Outputs="$(_BlazorLinkerOutputCache)"
- Condition="'$(BuildingInsideVisualStudio)' != 'true' OR '$(DeployOnBuild)' != 'true'">
-
- <PropertyGroup>
- <_BlazorLinkerAdditionalOptions>-l $(BlazorWebAssemblyI18NAssemblies) $(AdditionalMonoLinkerOptions)</_BlazorLinkerAdditionalOptions>
- </PropertyGroup>
-
- <ItemGroup>
- <_OldLinkedFile Include="$(_BlazorIntermediateLinkerOutputPath)*.dll" />
- <_OldLinkedFile Include="$(_BlazorIntermediateLinkerOutputPath)*.pdb" />
- </ItemGroup>
-
- <Delete Files="@(_OldLinkedFile)" />
-
- <BlazorILLink
- ILLinkPath="$(ComponentsWebAssemblyLinkerPath)"
- AssemblyPaths="@(_BlazorAssemblyToLink)"
- RootAssemblyNames="@(_BlazorLinkerRoot)"
- RootDescriptorFiles="@(BlazorLinkerDescriptor)"
- OutputDirectory="$(_BlazorIntermediateLinkerOutputPath)"
- ExtraArgs="$(_BlazorLinkerAdditionalOptions)"
- ToolExe="$(_DotNetHostFileName)"
- ToolPath="$(_DotNetHostDirectory)" />
-
- <ItemGroup>
- <_LinkerResult Include="$(_BlazorIntermediateLinkerOutputPath)*.dll" />
- <_LinkerResult Include="$(_BlazorIntermediateLinkerOutputPath)*.pdb" />
- </ItemGroup>
-
- <WriteLinesToFile File="$(_BlazorLinkerOutputCache)" Lines="@(_LinkerResult)" Overwrite="true" />
- </Target>
-
- <UsingTask TaskName="ResolveBlazorRuntimeDependencies" AssemblyFile="$(_BlazorTasksPath)" />
- <Target
- Name="_ResolveBlazorOutputsWhenNotLinked"
- DependsOnTargets="_ResolveBlazorRuntimeDependencies"
- Condition="'$(BlazorWebAssemblyEnableLinking)' != 'true'">
-
- <ReadLinesFromFile File="$(_BlazorApplicationAssembliesCacheFile)" Condition="'@(_BlazorResolvedAssembly->Count())' == '0'">
- <Output TaskParameter="Lines" ItemName="_BlazorResolvedAssembly"/>
- </ReadLinesFromFile>
-
- <ItemGroup>
- <!--
- Workaround for https://github.com/dotnet/aspnetcore/issues/19926. Add _BlazorResolvedAssembly to FileWrites so that these files
- do not get removed during an incremental build. Note that we add these files here as opposed to _ResolveBlazorRuntimeDependencies
- since the task that calculates these items in _ResolveBlazorRuntimeDependencies does not execute in incremental builds.
- -->
- <FileWrites Include="$(_BlazorResolvedAssembly)"/>
- </ItemGroup>
- </Target>
-
- <Target
- Name="_ResolveBlazorRuntimeDependencies"
- Inputs="$(ProjectAssetsFile);
- @(IntermediateAssembly);
- @(_BlazorManagedRuntimeAssembly)"
- Outputs="$(_BlazorApplicationAssembliesCacheFile)">
-
- <!--
- At this point we have decided not to run the linker and instead to just copy the assemblies
- from the BCL referenced by the app the nuget package into the _framework/_bin folder.
- The only thing we need to do here is collect the list of items that will go into _framework/_bin.
- -->
- <ResolveBlazorRuntimeDependencies
- EntryPoint="@(IntermediateAssembly)"
- ApplicationDependencies="@(_BlazorManagedRuntimeAssembly)"
- WebAssemblyBCLAssemblies="@(_WebAssemblyBCLAssembly)">
-
- <Output TaskParameter="Dependencies" ItemName="_BlazorResolvedAssemblyUnlinked" />
- </ResolveBlazorRuntimeDependencies>
-
- <ItemGroup Condition="'$(BlazorWebAssemblyI18NAssemblies)' != 'none'">
- <!--
- Unless the user has asked for no-assemblies, copy all I18N assemblies to the build output.
- We do not want to decipher the linker's format for passing in I18N options in our build targets
- -->
- <_BlazorResolvedAssemblyUnlinked Include="$(ComponentsWebAssemblyBaseClassLibraryPath)I18N*.dll" />
- </ItemGroup>
-
- <!--
- Workaround for https://github.com/dotnet/aspnetcore/issues/19926. Using the files from their initial locations
- as-is causes RazorSDK to remove files from a hosted app's publish directory. This is because files being removed
- are looked up by their path. We'll copy files to an intermediate location to avoid the removal code.
- -->
- <Copy
- SourceFiles="@(_BlazorResolvedAssemblyUnlinked)"
- DestinationFolder="$(_BlazorIntermediateOutputPath)unlinked">
- <Output TaskParameter="CopiedFiles" ItemName="_BlazorResolvedAssembly" />
- </Copy>
-
- <WriteLinesToFile File="$(_BlazorApplicationAssembliesCacheFile)" Lines="@(_BlazorResolvedAssembly)" Overwrite="true" />
-
- <ItemGroup>
- <FileWrites Include="$(_BlazorApplicationAssembliesCacheFile)" />
- </ItemGroup>
- </Target>
-
- <Target Name="_GenerateBlazorBootJsonInputHash">
- <ItemGroup>
- <_BlazorBootJsonHashInput Include="@(IntermediateAssembly)" />
- <_BlazorBootJsonHashInput Include="@(_BlazorOutputWithTargetPath)" />
- <_BlazorBootJsonHashInput Include="@(_BlazorConfigFile)" />
- </ItemGroup>
-
- <Hash ItemsToHash="@(_BlazorBootJsonHashInput)">
- <Output TaskParameter="HashResult" PropertyName="_BlazorBootJsonInputHash" />
- </Hash>
-
- <PropertyGroup>
- <_BlazorBootJsonInputHashFile>$(_BlazorIntermediateOutputPath)boot.json.input</_BlazorBootJsonInputHashFile>
- </PropertyGroup>
-
- <WriteLinesToFile
- Lines="$(_BlazorBootJsonInputHash)"
- File="$(_BlazorBootJsonInputHashFile)"
- Overwrite="True"
- WriteOnlyWhenDifferent="True" />
-
- </Target>
-
- <UsingTask TaskName="GenerateBlazorBootJson" AssemblyFile="$(_BlazorTasksPath)" />
-
- <Target
- Name="_GenerateBlazorBootJson"
- DependsOnTargets="_GenerateBlazorBootJsonInputHash"
- Inputs="$(MSBuildAllProjects);@(_BlazorOutputWithTargetPath);$(_BlazorBootJsonInputHashFile)"
- Outputs="$(_BlazorBootJsonIntermediateOutputPath)">
-
- <PropertyGroup>
- <_IsDebugBuild>false</_IsDebugBuild>
- <_IsDebugBuild Condition="'$(Configuration)' == 'Debug'">true</_IsDebugBuild>
- <BlazorCacheBootResources Condition="'$(BlazorCacheBootResources)' == ''">true</BlazorCacheBootResources>
- </PropertyGroup>
-
- <ItemGroup>
- <_BlazorBootResource Include="@(_BlazorOutputWithTargetPath->HasMetadata('BootManifestResourceType'))" />
- </ItemGroup>
-
- <GenerateBlazorBootJson
- AssemblyPath="@(IntermediateAssembly)"
- Resources="@(_BlazorBootResource)"
- DebugBuild="$(_IsDebugBuild)"
- LinkerEnabled="$(BlazorWebAssemblyEnableLinking)"
- CacheBootResources="$(BlazorCacheBootResources)"
- OutputPath="$(_BlazorBootJsonIntermediateOutputPath)"
- ConfigurationFiles="@(_BlazorConfigFile)" />
-
- </Target>
-
- <Target Name="_GenerateBlazorBootJsonIntegrity">
-
- <GetFileHash Files="$(_BlazorBootJsonIntermediateOutputPath)" Algorithm="SHA256" HashEncoding="base64">
- <Output TaskParameter="Items" ItemName="_BlazorBootJsonWithHash" />
- </GetFileHash>
-
- <ItemGroup>
-
- <_BlazorBootJsonWithIntegrity Include="@(_BlazorBootJsonWithHash)">
- <Integrity>%(FileHash)</Integrity>
- <IntegrityFile>$(IntermediateOutputPath)integrity\$([System.String]::Copy('%(FileHash)').Replace('/','-').Replace('+','_')).hash</IntegrityFile>
- </_BlazorBootJsonWithIntegrity>
-
- <_BlazorOutputWithTargetPath Include="@(_BlazorBootJsonWithIntegrity)" RemoveMetadata="FileHash;FileHashAlgorithm">
- <TargetOutputPath>$(_BaseBlazorRuntimeOutputPath)$(_BlazorBootJsonName)</TargetOutputPath>
- </_BlazorOutputWithTargetPath>
-
- <FileWrites Include="$(_BlazorBootJsonIntermediateOutputPath)" />
- <FileWrites Include="%(_BlazorBootJsonWithIntegrity.IntegrityFile)" />
-
- </ItemGroup>
-
- <WriteLinesToFile Lines="%(_BlazorBootJsonWithIntegrity.Integrity)" File="%(_BlazorBootJsonWithIntegrity.IntegrityFile)" WriteOnlyWhenDifferent="true" Overwrite="true" />
-
- </Target>
-
-</Project>
diff --git a/src/Components/WebAssembly/Build/src/targets/CollationLinkerDescriptor.xml b/src/Components/WebAssembly/Build/src/targets/CollationLinkerDescriptor.xml
deleted file mode 100644
index 693bdb6768..0000000000
--- a/src/Components/WebAssembly/Build/src/targets/CollationLinkerDescriptor.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<linker>
- <!-- This file disables exclusions that remove collation data -->
-
- <assembly fullname="mscorlib">
- <resource name="collation.cjkCHS.bin" action="remove"/>
- <resource name="collation.cjkCHT.bin" action="remove"/>
- <resource name="collation.cjkJA.bin" action="remove"/>
- <resource name="collation.cjkKO.bin" action="remove"/>
- <resource name="collation.cjkKOlv2.bin" action="remove"/>
- <resource name="collation.core.bin" action="remove"/>
- <resource name="collation.tailoring.bin" action="remove"/>
-
- <type fullname="System.Globalization.CompareInfo">
- <method signature="System.Boolean get_IgnoreCaseNotSupported()" body="stub" value="true"/>
- </type>
-
- <type fullname="System.Globalization.CompareInfo">
- <method signature="System.Boolean get_UseManagedCollation()" body="stub" value="false"/>
- </type>
- </assembly>
-</linker> \ No newline at end of file
diff --git a/src/Components/WebAssembly/Build/src/targets/Compression.targets b/src/Components/WebAssembly/Build/src/targets/Compression.targets
deleted file mode 100644
index 348d62481a..0000000000
--- a/src/Components/WebAssembly/Build/src/targets/Compression.targets
+++ /dev/null
@@ -1,108 +0,0 @@
-<Project>
- <PropertyGroup>
-
- <_BlazorBrotliPath>$(_BlazorToolsDir)compression\blazor-brotli.dll</_BlazorBrotliPath>
- <ResolveCurrentProjectStaticWebAssetsDependsOn>
- $(ResolveCurrentProjectStaticWebAssetsDependsOn);
- _ResolveBlazorFilesToCompress;
- </ResolveCurrentProjectStaticWebAssetsDependsOn>
-
- </PropertyGroup>
-
- <Target Name="_ResolveBlazorFilesToCompress" AfterTargets="_ResolveBlazorGeneratedAssets">
-
- <PropertyGroup>
- <_BlazorFilesIntermediateOutputPath>$(IntermediateOutputPath)compressed\</_BlazorFilesIntermediateOutputPath>
- <_GzipCompressionBlazorApplicationFilesManifestPath>$(IntermediateOutputPath)compressed\gzip.manifest.json</_GzipCompressionBlazorApplicationFilesManifestPath>
- <_BrotliCompressionBlazorApplicationFilesManifestPath>$(IntermediateOutputPath)compressed\brotli.manifest.json</_BrotliCompressionBlazorApplicationFilesManifestPath>
- </PropertyGroup>
-
- <MakeDir Directories="$(_BlazorFilesIntermediateOutputPath)" />
- <ItemGroup>
-
- <_CompressionCandidate Include="@(StaticWebAsset)" Condition="'%(SourceType)' == '' and $([System.String]::Copy('%(RelativePath)').Replace('\','/').StartsWith('_framework/'))" KeepDuplicates="false" />
- <_CompressionCandidateIntegrity Include="@(_BlazorOutputWithTargetPath->'%(FullPath)')" />
- <_CompressionCandidateWithIntegrity Include="%(Identity)">
- <SourceType>@(_CompressionCandidate->'%(SourceType)')</SourceType>
- <SourceId>@(_CompressionCandidate->'%(SourceId)')</SourceId>
- <ContentRoot>@(_CompressionCandidate->'%(ContentRoot)')</ContentRoot>
- <BasePath>@(_CompressionCandidate->'%(BasePath)')</BasePath>
- <RelativePath>@(_CompressionCandidate->'%(RelativePath)')</RelativePath>
- <InputSource>@(_CompressionCandidateIntegrity->'%(IntegrityFile)')</InputSource>
- </_CompressionCandidateWithIntegrity>
-
- <_GzipBlazorFileToCompress Include="@(_CompressionCandidateWithIntegrity)">
- <TargetCompressionPath>$(_BlazorFilesIntermediateOutputPath)%(RelativePath).gz</TargetCompressionPath>
- <TargetOutputPath>%(RelativePath).gz</TargetOutputPath>
- <RelativePath>%(RelativePath).gz</RelativePath>
- </_GzipBlazorFileToCompress>
- <_GzipBlazorFileToCompress Remove="@(_BlazorFileCompressExclusion)" />
-
- <_BrotliBlazorFileToCompress Include="@(_CompressionCandidateWithIntegrity)">
- <TargetCompressionPath>$(_BlazorFilesIntermediateOutputPath)%(RelativePath).br</TargetCompressionPath>
- <TargetOutputPath>%(RelativePath).br</TargetOutputPath>
- <RelativePath>%(RelativePath).br</RelativePath>
- </_BrotliBlazorFileToCompress>
- <_BrotliBlazorFileToCompress Remove="@(_BlazorFileCompressExclusion)" />
-
- <_BlazorFileToCompress Include="@(_GzipBlazorFileToCompress)" />
- <_BlazorFileToCompress Include="@(_BrotliBlazorFileToCompress)" />
- <_BlazorFileToCompress Remove="@(_BlazorFileCompressExclusion)" />
-
- <_CompressedStaticWebAsset Include="@(_BlazorFileToCompress->'%(TargetCompressionPath)')" RemoveMetadata="TargetOutputPath;TargetCompressionPath" />
-
- <StaticWebAsset Include="@(_CompressedStaticWebAsset->'%(FullPath)')" KeepMetadata="SourceType;SourceId;ContentRoot;BasePath;RelativePath" />
- <FileWrites Include="@(_CompressedStaticWebAsset)" />
-
- </ItemGroup>
-
- </Target>
-
- <UsingTask TaskName="GzipCompressBlazorApplicationFiles" AssemblyFile="$(_BlazorTasksPath)" />
- <UsingTask TaskName="BrotliCompressBlazorApplicationFiles" AssemblyFile="$(_BlazorTasksPath)" />
- <UsingTask TaskName="GenerateBlazorCompressionManifest" AssemblyFile="$(_BlazorTasksPath)" />
-
- <Target
- Name="_GzipCompressBlazorApplicationFiles"
- DependsOnTargets="ResolveStaticWebAssetsInputs"
- BeforeTargets="_BlazorStaticWebAssetsCopyGeneratedFilesToOutputDirectory"
- Inputs="$(_GzipCompressionBlazorApplicationFilesManifestPath)"
- Outputs="@(_GzipBlazorFileToCompress->'%(TargetCompressionPath)')">
-
- <GzipCompressBlazorApplicationFiles ManifestPath="$(_GzipCompressionBlazorApplicationFilesManifestPath)" />
-
- </Target>
-
- <Target
- Name="_GenerateGzipCompressionBlazorApplicationFilesManifest"
- BeforeTargets="_GzipCompressBlazorApplicationFiles"
- Inputs="@(_GzipBlazorFileToCompress->'%(InputSource)')"
- Outputs="$(_GzipCompressionBlazorApplicationFilesManifestPath)">
-
- <GenerateBlazorCompressionManifest FilesToCompress="@(_GzipBlazorFileToCompress)" ManifestPath="$(_GzipCompressionBlazorApplicationFilesManifestPath)" />
- </Target>
-
- <Target
- Name="_BrotliCompressBlazorApplicationFiles"
- BeforeTargets="GetCopyToPublishDirectoryItems;_CopyResolvedFilesToPublishPreserveNewest"
- DependsOnTargets="ResolveStaticWebAssetsInputs"
- Inputs="$(_BrotliCompressionBlazorApplicationFilesManifestPath)"
- Outputs="@(_BrotliBlazorFileToCompress->'%(TargetCompressionPath)')">
-
- <BrotliCompressBlazorApplicationFiles
- BlazorBrotliPath="$(_BlazorBrotliPath)"
- ManifestPath="$(_BrotliCompressionBlazorApplicationFilesManifestPath)"
- ToolExe="$(_DotNetHostFileName)"
- ToolPath="$(_DotNetHostDirectory)" />
- </Target>
-
- <Target
- Name="_GenerateBrotliCompressionBlazorApplicationFilesManifest"
- BeforeTargets="_GzipCompressBlazorApplicationFiles"
- Inputs="@(_BrotliBlazorFileToCompress->'%(InputSource)')"
- Outputs="$(_BrotliCompressionBlazorApplicationFilesManifestPath)">
-
- <GenerateBlazorCompressionManifest FilesToCompress="@(_BrotliBlazorFileToCompress)" ManifestPath="$(_BrotliCompressionBlazorApplicationFilesManifestPath)" />
- </Target>
-
-</Project>
diff --git a/src/Components/WebAssembly/Build/src/targets/Publish.targets b/src/Components/WebAssembly/Build/src/targets/Publish.targets
deleted file mode 100644
index 5847bb0aca..0000000000
--- a/src/Components/WebAssembly/Build/src/targets/Publish.targets
+++ /dev/null
@@ -1,40 +0,0 @@
-<Project>
- <PropertyGroup>
- <!-- Disable unwanted parts of the default publish process -->
- <CopyBuildOutputToPublishDirectory>false</CopyBuildOutputToPublishDirectory>
- <CopyOutputSymbolsToPublishDirectory>false</CopyOutputSymbolsToPublishDirectory>
- <PreserveCompilationContext>false</PreserveCompilationContext>
- <RazorCompileOnPublish>false</RazorCompileOnPublish>
- <GenerateDependencyFile>false</GenerateDependencyFile>
- <IsWebConfigTransformDisabled>true</IsWebConfigTransformDisabled>
- </PropertyGroup>
-
- <Target
- Name="_BlazorCleanupPublishOutput"
- AfterTargets="ComputeResolvedFilesToPublishList"
- Condition="'$(BlazorPrunePublishOutput)' != 'false'">
-
- <ItemGroup>
- <!-- Delete stray contents from the root of the the app. -->
- <ResolvedFileToPublish
- Remove="%(ResolvedFileToPublish.Identity)"
- Condition="'%(ResolvedFileToPublish.RelativePath)' != 'web.config' AND !$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))"/>
- </ItemGroup>
- </Target>
-
- <Target
- Name="_BlazorCopyStandaloneWebConfig"
- AfterTargets="_BlazorCleanupPublishOutput;ComputeResolvedFilesToPublishList"
- Condition="'@(ResolvedFileToPublish->AnyHaveMetadataValue('RelativePath', 'web.config'))' != 'true'">
-
- <ItemGroup>
- <ResolvedFileToPublish Include="$(MSBuildThisFileDirectory)Standalone.Web.config">
- <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
- <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
- <RelativePath>web.config</RelativePath>
- </ResolvedFileToPublish>
- </ItemGroup>
-
- </Target>
-
-</Project> \ No newline at end of file
diff --git a/src/Components/WebAssembly/Build/src/targets/ServiceWorkerAssetsManifest.targets b/src/Components/WebAssembly/Build/src/targets/ServiceWorkerAssetsManifest.targets
deleted file mode 100644
index c17edf60e0..0000000000
--- a/src/Components/WebAssembly/Build/src/targets/ServiceWorkerAssetsManifest.targets
+++ /dev/null
@@ -1,240 +0,0 @@
-<Project>
-
- <Target Name="_ComputeServiceWorkerAssetsManifestInputs"
- Condition="'$(ServiceWorkerAssetsManifest)' != ''"
- BeforeTargets="_ResolveBlazorOutputs;_ResolveBlazorFilesToCompress">
-
- <PropertyGroup>
- <_ServiceWorkerAssetsManifestIntermediateOutputPath>$([MSBuild]::MakeRelative($(MSBuildProjectDirectory), $(_BlazorIntermediateOutputPath)))$(ServiceWorkerAssetsManifest)</_ServiceWorkerAssetsManifestIntermediateOutputPath>
- <_ServiceWorkerAssetsManifestFullPath>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)/$(_ServiceWorkerAssetsManifestIntermediateOutputPath)'))</_ServiceWorkerAssetsManifestFullPath>
- </PropertyGroup>
-
- <ItemGroup>
- <_BlazorOutputWithTargetPath
- Include="$(_ServiceWorkerAssetsManifestFullPath)"
- TargetOutputPath="$(_ServiceWorkerAssetsManifestIntermediateOutputPath)" />
-
- <_ManifestStaticWebAsset Include="$(_ServiceWorkerAssetsManifestFullPath)">
- <SourceType></SourceType>
- <SourceId>$(PackageId)</SourceId>
- <ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
- <BasePath>$(StaticWebAssetBasePath)</BasePath>
- <RelativePath>$(ServiceWorkerAssetsManifest)</RelativePath>
- </_ManifestStaticWebAsset>
-
- <StaticWebAsset Include="@(_ManifestStaticWebAsset)" />
- <_CompressionCandidate Include="@(_ManifestStaticWebAsset)" />
- <_CompressionCandidateWithIntegrity Include="@(_ManifestStaticWebAsset)">
- <InputSource>$(_ServiceWorkerAssetsManifestFullPath)</InputSource>
- </_CompressionCandidateWithIntegrity>
-
- </ItemGroup>
-
- </Target>
-
- <UsingTask TaskName="GenerateServiceWorkerAssetsManifest" AssemblyFile="$(_BlazorTasksPath)" />
-
- <Target Name="_WriteServiceWorkerAssetsManifest"
- Condition="'$(ServiceWorkerAssetsManifest)' != ''"
- Inputs="@(ServiceWorkerAssetsManifestItem)"
- Outputs="$(_ServiceWorkerAssetsManifestIntermediateOutputPath)"
- BeforeTargets="_ComputeManifestIntegrity"
- DependsOnTargets="ResolveStaticWebAssetsInputs;_GenerateServiceWorkerIntermediateFiles">
-
- <GenerateServiceWorkerAssetsManifest
- Version="$(ServiceWorkerAssetsManifestVersion)"
- AssetsWithHashes="@(_ServiceWorkerAssetsManifestItemWithHash)"
- OutputPath="$(_ServiceWorkerAssetsManifestIntermediateOutputPath)" />
-
- <ItemGroup>
- <FileWrites Include="$(_ServiceWorkerAssetsManifestIntermediateOutputPath)" />
- </ItemGroup>
-
- </Target>
-
- <Target Name="_ComputeManifestIntegrity"
- Condition="'$(ServiceWorkerAssetsManifest)' != ''"
- BeforeTargets="_BlazorStaticWebAssetsCopyGeneratedFilesToOutputDirectory;_GzipCompressBlazorApplicationFiles">
-
- <GetFileHash Files="$(_ServiceWorkerAssetsManifestIntermediateOutputPath)" Algorithm="SHA256" HashEncoding="base64">
- <Output TaskParameter="Items" ItemName="_ServiceWorkerManifestWithHash" />
- </GetFileHash>
-
- <ItemGroup>
-
- <_ServiceWorkerManifestWithIntegrity Include="@(_ServiceWorkerManifestWithHash)">
- <Integrity>%(FileHash)</Integrity>
- <IntegrityFile>$(IntermediateOutputPath)integrity\$([System.String]::Copy('%(FileHash)').Replace('/','-').Replace('+','_')).hash</IntegrityFile>
- </_ServiceWorkerManifestWithIntegrity>
-
- <FileWrites Include="%(_ServiceWorkerManifestWithIntegrity.IntegrityFile)" />
-
- </ItemGroup>
-
- <WriteLinesToFile Lines="%(_ServiceWorkerManifestWithIntegrity.Integrity)" File="%(_ServiceWorkerManifestWithIntegrity.IntegrityFile)" WriteOnlyWhenDifferent="true" Overwrite="true" />
-
- <PropertyGroup>
- <_ServiceWorkerManifestIntegrityFile>$(IntermediateOutputPath)integrity\$([System.String]::Copy('%(_ServiceWorkerManifestWithIntegrity.FileHash)').Replace('/','-').Replace('+','_')).hash</_ServiceWorkerManifestIntegrityFile>
- </PropertyGroup>
-
- <ItemGroup>
- <_GzipFileToPatch Include="@(_GzipBlazorFileToCompress)" Condition="'%(Identity)' == '$(_ServiceWorkerAssetsManifestFullPath)'" KeepDuplicates="false">
- <InputSource>$(_ServiceWorkerManifestIntegrityFile)</InputSource>
- </_GzipFileToPatch>
-
- <_GzipBlazorFileToCompress Remove="@(_GzipFileToPatch)" />
- <_GzipBlazorFileToCompress Include="@(_GzipFileToPatch)" />
-
- <_BrotliFileToPatch Include="@(_BrotliBlazorFileToCompress)" Condition="'%(Identity)' == '$(_ServiceWorkerAssetsManifestFullPath)'" KeepDuplicates="false">
- <InputSource>$(_ServiceWorkerManifestIntegrityFile)</InputSource>
- </_BrotliFileToPatch>
-
- <_BrotliBlazorFileToCompress Remove="@(_BrotliFileToPatch)" />
- <_BrotliBlazorFileToCompress Include="@(_BrotliFileToPatch)" />
- </ItemGroup>
-
- </Target>
-
- <Target Name="_ComputeServiceWorkerAssetsManifestFileHashes"
- Condition="'$(ServiceWorkerAssetsManifest)' != ''"
- DependsOnTargets="ResolveStaticWebAssetsInputs;_BlazorComputeOtherAssetsIntegrity">
-
- <ItemGroup>
- <ServiceWorkerAssetsManifestItem
- Include="%(StaticWebAsset.Identity)"
- Condition="'%(RelativePath)' != '$(ServiceWorkerAssetsManifest)'">
- <AssetUrl>$([System.String]::Copy('$([System.String]::Copy('%(StaticWebAsset.BasePath)').TrimEnd('/'))/%(StaticWebAsset.RelativePath)').Replace('\','/').TrimStart('/'))</AssetUrl>
- </ServiceWorkerAssetsManifestItem>
-
- <!-- Don't include compressed files in the manifest, since their existence is transparent to the client -->
- <ServiceWorkerAssetsManifestItem Remove="@(_CompressedStaticWebAsset->'%(FullPath)')" />
-
- <!-- Don't include the service worker files in the manifest, as the service worker doesn't need to fetch itself -->
- <ServiceWorkerAssetsManifestItem Remove="%(_ServiceWorkerIntermediateFile.FullPath)" />
-
- <_ServiceWorkerExclude Include="@(_StaticWebAssetIntegrity)" />
- <_ServiceWorkerItemBase Include="@(ServiceWorkerAssetsManifestItem)" />
- <_ServiceWorkerItemBase Remove="@(_ServiceWorkerExclude)" />
- <_ServiceWorkerItemHash Include="@(ServiceWorkerAssetsManifestItem)" />
- <_ServiceWorkerItemHash Remove="@(_ServiceWorkerItemBase)" />
- <_ServiceWorkerAssetsManifestItemWithHash Include="%(Identity)">
- <AssetUrl>@(_ServiceWorkerItemHash->'%(AssetUrl)')</AssetUrl>
- <Integrity>@(_StaticWebAssetIntegrity->'%(Integrity)')</Integrity>
- </_ServiceWorkerAssetsManifestItemWithHash>
-
- </ItemGroup>
- </Target>
-
- <Target Name="_BlazorComputeOtherAssetsIntegrity" Condition="'$(ServiceWorkerAssetsManifest)' != ''">
- <ItemGroup>
- <_StaticWebAssetsWithoutHash Include="@(StaticWebAsset)" Condition="'%(SourceType)' != '' or '%(ContentRoot)' == '$(_BlazorCurrentProjectWWWroot)'" />
- <_StaticWebAssetsWithoutHash Remove="@(_StaticWebAssetIntegrity)" />
- </ItemGroup>
-
- <GetFileHash Files="@(_StaticWebAssetsWithoutHash)" Algorithm="SHA256" HashEncoding="base64">
- <Output TaskParameter="Items" ItemName="_StaticWebAssetHash" />
- </GetFileHash>
-
- <ItemGroup>
- <_StaticWebAssetIntegrity Include="%(_StaticWebAssetHash.Identity)">
- <Integrity>%(_StaticWebAssetHash.FileHash)</Integrity>
- </_StaticWebAssetIntegrity>
- </ItemGroup>
-
- </Target>
-
-
- <!--
- Compute a default ServiceWorkerAssetsManifestVersion value by combining all the asset hashes.
- This is useful because then clients will only have to repopulate caches if the contents have changed.
- -->
- <Target Name="_ComputeDefaultServiceWorkerAssetsManifestVersion"
- Condition="'$(ServiceWorkerAssetsManifest)' != ''"
- DependsOnTargets="_ComputeServiceWorkerAssetsManifestFileHashes">
- <PropertyGroup>
- <_CombinedHashIntermediatePath>$(_BlazorIntermediateOutputPath)serviceworkerhashes.txt</_CombinedHashIntermediatePath>
- </PropertyGroup>
-
- <!-- Neither of these should ever happen, but if we do we want to know about it. -->
- <Error Text="Cannot compute service worker assets manifest version, because no service worker manifest items were defined."
- Condition="'@(_ServiceWorkerAssetsManifestItemWithHash)' == ''" />
- <Error Text="While computing service worker assets manifest version, did not find any dll entries in service worker assets manifest."
- Condition="'@(_ServiceWorkerAssetsManifestItemWithHash->WithMetadataValue('Extension', '.dll'))' == ''" />
-
- <WriteLinesToFile
- File="$(_CombinedHashIntermediatePath)"
- Lines="@(_ServiceWorkerAssetsManifestItemWithHash->'%(Integrity)')"
- WriteOnlyWhenDifferent="true"
- Overwrite="true" />
-
- <GetFileHash Files="$(_CombinedHashIntermediatePath)" Algorithm="SHA256" HashEncoding="base64">
- <Output TaskParameter="Items" ItemName="_ServiceWorkerAssetsManifestCombinedHash" />
- </GetFileHash>
-
- <PropertyGroup>
- <ServiceWorkerAssetsManifestVersion Condition="'$(ServiceWorkerAssetsManifestVersion)' == ''">$([System.String]::Copy('%(_ServiceWorkerAssetsManifestCombinedHash.FileHash)').Substring(0, 8))</ServiceWorkerAssetsManifestVersion>
- </PropertyGroup>
- </Target>
-
- <Target Name="_OmitServiceWorkerContent"
- Condition="'$(ServiceWorkerAssetsManifest)' != ''"
- BeforeTargets="AssignTargetPaths;ResolveCurrentProjectStaticWebAssetsInputs">
-
- <ItemGroup>
- <!-- Don't emit the service worker source files to the output -->
- <Content Remove="@(ServiceWorker)" />
- <Content Remove="@(ServiceWorker->'%(PublishedContent)')" />
- </ItemGroup>
- </Target>
-
- <Target Name="_ResolveServiceWorkerOutputs"
- Condition="'$(ServiceWorkerAssetsManifest)' != ''"
- BeforeTargets="_ResolveBlazorOutputs"
- DependsOnTargets="_ComputeServiceWorkerOutputs">
-
- <ItemGroup>
- <_BlazorFileCompressExclusion Include="@(_ServiceWorkerIntermediateFile->'%(FullPath)')" />
-
- <_ServiceWorkerStaticWebAsset Include="@(_ServiceWorkerIntermediateFile->'%(FullPath)')">
- <SourceType></SourceType>
- <SourceId>$(PackageId)</SourceId>
- <ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
- <BasePath>$(StaticWebAssetBasePath)</BasePath>
- <RelativePath>%(TargetOutputPath)</RelativePath>
- </_ServiceWorkerStaticWebAsset>
-
- <StaticWebAsset Include="@(_ServiceWorkerStaticWebAsset)" />
-
- </ItemGroup>
- </Target>
-
- <Target Name="_ComputeServiceWorkerOutputs"
- Condition="'$(ServiceWorkerAssetsManifest)' != ''">
-
- <ItemGroup>
- <!-- Figure out where we're getting the content for each @(ServiceWorker) entry, depending on whether there's a PublishedContent value -->
- <_ServiceWorkerIntermediateFile Include="@(ServiceWorker->'$(IntermediateOutputPath)blazor\serviceworkers\%(Identity)')">
- <ContentSourcePath Condition="'%(ServiceWorker.PublishedContent)' != ''">%(ServiceWorker.PublishedContent)</ContentSourcePath>
- <ContentSourcePath Condition="'%(ServiceWorker.PublishedContent)' == ''">%(ServiceWorker.Identity)</ContentSourcePath>
- <TargetOutputPath>%(ServiceWorker.Identity)</TargetOutputPath>
- <TargetOutputPath Condition="$([System.String]::Copy('%(ServiceWorker.Identity)').Replace('\','/').StartsWith('wwwroot/'))">$([System.String]::Copy('%(ServiceWorker.Identity)').Substring(8))</TargetOutputPath>
- </_ServiceWorkerIntermediateFile>
- </ItemGroup>
- </Target>
-
- <Target Name="_GenerateServiceWorkerIntermediateFiles"
- Condition="'$(ServiceWorkerAssetsManifest)' != ''"
- Inputs="@(_ServiceWorkerIntermediateFile->'%(ContentSourcePath)'); $(_CombinedHashIntermediatePath)"
- Outputs="@(_ServiceWorkerIntermediateFile)"
- DependsOnTargets="_ComputeDefaultServiceWorkerAssetsManifestVersion">
- <Copy SourceFiles="%(_ServiceWorkerIntermediateFile.ContentSourcePath)" DestinationFiles="%(_ServiceWorkerIntermediateFile.Identity)" />
- <WriteLinesToFile
- File="%(_ServiceWorkerIntermediateFile.Identity)"
- Lines="/* Manifest version: $(ServiceWorkerAssetsManifestVersion) */"
- Condition="'$(ServiceWorkerAssetsManifestVersion)' != ''" />
- <ItemGroup>
- <FileWrites Include="%(_ServiceWorkerIntermediateFile.Identity)" />
- </ItemGroup>
- </Target>
-
-</Project>
diff --git a/src/Components/WebAssembly/Build/src/targets/StaticWebAssets.props b/src/Components/WebAssembly/Build/src/targets/StaticWebAssets.props
deleted file mode 100644
index d15d07d729..0000000000
--- a/src/Components/WebAssembly/Build/src/targets/StaticWebAssets.props
+++ /dev/null
@@ -1,15 +0,0 @@
-<Project>
- <PropertyGroup>
- <ResolveStaticWebAssetsInputsDependsOn>
- $(ResolveStaticWebAssetsInputsDependsOn);
- _BlazorApplyLinkPreferencesToStaticWebAssets;
- _ResolveBlazorGeneratedAssets;
- </ResolveStaticWebAssetsInputsDependsOn>
-
- <GetCurrentProjectStaticWebAssetsDependsOn>
- $(GetCurrentProjectStaticWebAssetsDependsOn);
- _BlazorApplyLinkPreferencesToStaticWebAssets;
- _ResolveBlazorGeneratedAssets;
- </GetCurrentProjectStaticWebAssetsDependsOn>
- </PropertyGroup>
-</Project>
diff --git a/src/Components/WebAssembly/Build/src/targets/StaticWebAssets.targets b/src/Components/WebAssembly/Build/src/targets/StaticWebAssets.targets
deleted file mode 100644
index 9c16d9dd5a..0000000000
--- a/src/Components/WebAssembly/Build/src/targets/StaticWebAssets.targets
+++ /dev/null
@@ -1,165 +0,0 @@
-<Project>
-
- <PropertyGroup>
- <_BlazorCurrentProjectWWWroot>$([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)\wwwroot\'))</_BlazorCurrentProjectWWWroot>
- </PropertyGroup>
-
- <Target Name="_ResolveBlazorGeneratedAssets" DependsOnTargets="_PrepareBlazorOutputs">
- <ItemGroup>
- <_BlazorOutputCandidateAsset Include="@(_BlazorOutputWithTargetPath->'%(FullPath)')">
- <SourceType></SourceType>
- <SourceId>$(PackageId)</SourceId>
- <ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
- <BasePath>$(StaticWebAssetBasePath)</BasePath>
- <RelativePath>$([System.String]::Copy('%(_BlazorOutputWithTargetPath.TargetOutputPath)').Replace('\','/'))</RelativePath>
- <Integrity>%(_BlazorOutputWithTargetPath.Integrity)</Integrity>
- </_BlazorOutputCandidateAsset>
-
- <_BlazorOutputCandidateAsset Remove="@(StaticWebAsset)" />
-
- <_StaticWebAssetIntegrity Include="@(_BlazorOutputCandidateAsset)" KeepMetadata="Integrity" />
-
- <StaticWebAsset Include="@(_BlazorOutputCandidateAsset)" KeepMetadata="SourceType;SourceId;ContentRoot;BasePath;RelativePath" />
-
- <StaticWebAsset Remove="@(StaticWebAsset)" Condition="'$(BlazorEnableDebugging)' != 'true' and '%(SourceType)' == '' and '%(Extension)' == '.pdb'" />
-
- <!-- We are depending on a "private" property for static web assets, but this is something we can clean-up in a later release.
- These files are not "external" in the "traditional" sense but it is fine for now as this is an implementation detail.
- We only need to do this for the standalone case, for hosted scenarios this works just fine as the assets are considered
- external. -->
- <_ExternalStaticWebAsset Include="@(_BlazorOutputWithTargetPath->'%(FullPath)')">
- <SourceId>$(PackageId)</SourceId>
- <!-- We just do this to keep the existing implementation happy. We will update this in the next release. -->
- <SourceType>Generated</SourceType>
- <ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
- <BasePath>$(StaticWebAssetBasePath)</BasePath>
- </_ExternalStaticWebAsset>
-
- <!-- These items we are adding for forward-compatibility with newer SDK versions. The paths listed here will be added unconditionally
- to the generated static web assets manifest. This is only needed for forward compatibility in Blazor standalone scenarios. -->
- <StaticWebAssetsManifestPath Include="$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))">
- <SourceId>$(PackageId)</SourceId>
- <BasePath>$(StaticWebAssetBasePath)</BasePath>
- </StaticWebAssetsManifestPath>
- </ItemGroup>
-
- </Target>
-
- <Target Name="_BlazorStaticWebAssetsCopyGeneratedFilesToOutputDirectory"
- DependsOnTargets="ResolveStaticWebAssetsInputs;$(_BlazorCopyFilesToOutputDirectoryDependsOn)"
- AfterTargets="CopyFilesToOutputDirectory"
- Condition="'$(OutputType.ToLowerInvariant())'=='exe'">
-
- <ItemGroup>
- <_BlazorCopyLocalAssets
- Include="@(StaticWebAsset)"
- Condition="'%(SourceType)' == '' and '%(ContentRoot)' != '$(_BlazorCurrentProjectWWWroot)' and !$([System.String]::Copy('%(RelativePath)').EndsWith('.br'))" />
- <_BlazorCopyLocalAssets Remove="@(_BlazorCopyLocalExclusion)" />
- </ItemGroup>
-
- <!-- Copy the blazor output files -->
- <Copy
- SourceFiles="@(_BlazorCopyLocalAssets)"
- DestinationFiles="@(_BlazorCopyLocalAssets->'%(ContentRoot)%(RelativePath)')"
- SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
- OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
- Retries="$(CopyRetryCount)"
- RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
- UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
- UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
- Condition="'@(_BlazorCopyLocalAssets)' != '' and '$(CopyBuildOutputToOutputDirectory)' == 'true' and '$(SkipCopyBuildProduct)' != 'true'">
- </Copy>
-
- <ItemGroup>
- <FileWrites Include="@(_BlazorCopyLocalAssets->'%(ContentRoot)%(RelativePath)')" />
- </ItemGroup>
-
- <ItemGroup>
- <_BlazorStatisticsOutput Include="@(_BlazorCopyLocalAssets->'%(RelativePath)')" />
- </ItemGroup>
-
- <Message Importance="high" Text="$(TargetName) (Blazor output) -> $(TargetDir)wwwroot" />
- </Target>
-
- <Target Name="_StaticWebAssetsBlazorStandalonePublish"
- AfterTargets="_StaticWebAssetsComputeFilesToPublish">
-
- <ItemGroup>
-
- <_CurrentProjectStandalonePublishStaticWebAsset Include="%(StaticWebAsset.FullPath)" Condition="'%(StaticWebAsset.SourceType)' == ''">
- <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
- <RelativePath>$([MSBuild]::MakeRelative('$(MSBuildProjectDirectory)','$([MSBuild]::NormalizePath('wwwroot\%(BasePath)\%(RelativePath)'))'))</RelativePath>
- </_CurrentProjectStandalonePublishStaticWebAsset>
-
- <!-- Remove any existing external static web asset that might have been added as part of the
- regular publish pipeline. -->
- <ResolvedFileToPublish Remove="@(_CurrentProjectStandalonePublishStaticWebAsset)" />
-
- <ResolvedFileToPublish Include="@(_CurrentProjectStandalonePublishStaticWebAsset)">
- <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
- </ResolvedFileToPublish>
-
- </ItemGroup>
-
- </Target>
-
- <Target Name="_BlazorApplyLinkPreferencesToStaticWebAssets">
- <ItemGroup>
- <_ContentWithWwrootLinkAttribute Include="@(Content)" Condition="'%(Content.Link)' != '' and $([System.String]::Copy('%(Content.Link)').Replace('\','/').StartsWith('wwwroot/'))" />
-
- <_ContentLinkedIntoWwwroot
- Include="@(_ContentWithWwrootLinkAttribute)"
- Condition="@(_ContentWithWwrootLinkAttribute) != '' and '%(_ContentWithWwrootLinkAttribute.CopyToPublishDirectory)' != 'false'">
- <!-- This gets rid of wwwroot\ -->
- <RelativePath>$([System.String]::Copy('%(Link)').Substring(8))</RelativePath>
- </_ContentLinkedIntoWwwroot>
-
- <_OutsideContentLinkedIntoWwwroot Include="@(_ContentLinkedIntoWwwroot->'%(FullPath)')" Condition="@(_ContentLinkedIntoWwwroot) != '' and !$([System.String]::Copy('%(Identity)').Replace('\','/').StartsWith('wwwroot/'))" />
- <_WwwrootLinkedContent Include="@(_ContentLinkedIntoWwwroot->'%(FullPath)')" Condition="@(_ContentLinkedIntoWwwroot) != '' and $([System.String]::Copy('%(Identity)').Replace('\','/').StartsWith('wwwroot/'))" KeepMetadata="RelativePath" />
-
- <!-- For content items with the Link attribute on them, we update the relative path. This enables support at publish time for these assets but forgoes any
- dev-time support. (If you want to have dev-time support, you need to add an appropriate file into the wwwroot folder with CopyToPublishDirectory="false")
- -->
- <_NonLinkedStaticWebAssets Include="@(StaticWebAsset)" Exclude="@(_WwwrootLinkedContent)" />
- <_LinkedStaticWebAssets Include="@(StaticWebAsset)" Exclude="@(_NonLinkedStaticWebAssets)" />
-
- <_UpdatedStaticWebAssets Include="%(Identity)">
- <SourceType>@(_LinkedStaticWebAssets->'%(SourceType)')</SourceType>
- <SourceId>@(_LinkedStaticWebAssets->'%(SourceId)')</SourceId>
- <ContentRoot>@(_LinkedStaticWebAssets->'%(ContentRoot)')</ContentRoot>
- <BasePath>@(_LinkedStaticWebAssets->'%(BasePath)')</BasePath>
- <RelativePath>@(_WwwrootLinkedContent->'%(RelativePath)')</RelativePath>
- </_UpdatedStaticWebAssets>
-
- <StaticWebAsset Remove="@(_UpdatedStaticWebAssets)" />
- <StaticWebAsset Include="@(_UpdatedStaticWebAssets)" />
-
- <!-- This allows limited publish time support for content items that are outside the wwwroot folder but are linked into the wwwroot folder. For example:
- * Imagine a set of items in <ProjectDir>/Client/publish that are linked into <ProjectDir>/wwwroot/.
- * We will consider them static web assets and default their content root to `<ProjectDir>/wwwroot` and their relative path will be whatever is after wwwroot\
- * We don't guarantee that these assets can be resolved at development time.
- * We do guarantee that we will copy them into the actual wwwroot folder at publish time.
- * If you want this type of dev-time support, the recomendation is to add the list of assets to the item group manually indicating a suitable content root.
- -->
- <StaticWebAsset Include="@(_OutsideContentLinkedIntoWwwroot)" Condition="@(_OutsideContentLinkedIntoWwwroot) != ''">
- <SourceType></SourceType>
- <SourceId>$(PackageId)</SourceId>
- <!-- We don't try to come up with a separate content root to make the inner loop work.
- You can add items with CopyToPublishDirectory=false for development time support or add the assets directly by pasing in the parameters
- -->
- <ContentRoot>$([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)\wwwroot\'))</ContentRoot>
- <BasePath>$(StaticWebAssetBasePath)</BasePath>
- <RelativePath>%(_OutsideContentLinkedIntoWwwroot.RelativePath)</RelativePath>
- </StaticWebAsset>
-
- <_StaticWebAssetsPublishFalse Include="@(Content->'%(FullPath)')" Condition="'%(Content.CopyToPublishDirectory)' == 'false'" />
- <_StaticWebAssetsLinkOutsideWwwroot Include="@(Content->'%(FullPath)')" Condition="'%(Content.Link)' != '' and !$([System.String]::Copy('%(Content.Link)').Replace('\','/').StartsWith('wwwroot/'))" />
-
- <!-- Remove files that wouldn't be copied to the publish folder or that would be copied outside of the wwwroot folder if they were ever considered static web assets -->
- <StaticWebAsset Remove="@(_StaticWebAssetsPublishFalse)" />
- <StaticWebAsset Remove="@(_StaticWebAssetsLinkOutsideWwwroot)" />
- </ItemGroup>
-
- </Target>
-
-</Project>
diff --git a/src/Components/WebAssembly/Build/test/BlazorCreateRootDescriptorFileTest.cs b/src/Components/WebAssembly/Build/test/BlazorCreateRootDescriptorFileTest.cs
deleted file mode 100644
index 2ad0ecdddd..0000000000
--- a/src/Components/WebAssembly/Build/test/BlazorCreateRootDescriptorFileTest.cs
+++ /dev/null
@@ -1,38 +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 System.IO;
-using System.Xml.Linq;
-using Xunit;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- public class BlazorCreateRootDescriptorFileTest
- {
- [Fact]
- public void ProducesRootDescriptor()
- {
- // Arrange/Act
- using var stream = new MemoryStream();
-
- // Act
- BlazorCreateRootDescriptorFile.WriteRootDescriptor(
- stream,
- new[] { "MyApp.dll" });
-
- // Assert
- stream.Position = 0;
- var document = XDocument.Load(stream);
- var rootElement = document.Root;
-
- var assemblyElement = Assert.Single(rootElement.Elements());
- Assert.Equal("assembly", assemblyElement.Name.ToString());
- Assert.Equal("MyApp.dll", assemblyElement.Attribute("fullname").Value);
-
- var typeElement = Assert.Single(assemblyElement.Elements());
- Assert.Equal("type", typeElement.Name.ToString());
- Assert.Equal("*", typeElement.Attribute("fullname").Value);
- Assert.Equal("true", typeElement.Attribute("required").Value);
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/Assert.cs b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/Assert.cs
deleted file mode 100644
index aaf3e508b5..0000000000
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/Assert.cs
+++ /dev/null
@@ -1,1006 +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 System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.IO.Compression;
-using System.Linq;
-using System.Reflection.Metadata;
-using System.Reflection.PortableExecutable;
-using System.Security.Cryptography;
-using System.Text;
-using System.Text.RegularExpressions;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- internal class Assert : Xunit.Assert
- {
- // Matches `{filename}: error {code}: {message} [{project}]
- // See https://stackoverflow.com/questions/3441452/msbuild-and-ignorestandarderrorwarningformat/5180353#5180353
- private static readonly Regex ErrorRegex = new Regex(@"^(?'location'.+): error (?'errorcode'[A-Z0-9]+): (?'message'.+) \[(?'project'.+)\]$");
- private static readonly Regex WarningRegex = new Regex(@"^(?'location'.+): warning (?'errorcode'[A-Z0-9]+): (?'message'.+) \[(?'project'.+)\]$");
- private static readonly string[] AllowedBuildWarnings = new[]
- {
- "MSB3491" , // The process cannot access the file. As long as the build succeeds, we're ok.
- "NETSDK1071", // "A PackageReference to 'Microsoft.NETCore.App' specified a Version ..."
- };
-
- public static void BuildPassed(MSBuildResult result, bool allowWarnings = false)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- if (result.ExitCode != 0)
- {
- throw new BuildFailedException(result);
- }
-
- var buildWarnings = GetBuildWarnings(result)
- .Where(m => !AllowedBuildWarnings.Contains(m.match.Groups["errorcode"].Value))
- .Select(m => m.line);
-
- if (!allowWarnings && buildWarnings.Any())
- {
- throw new BuildWarningsException(result, buildWarnings);
- }
- }
-
- public static void BuildError(MSBuildResult result, string errorCode, string location = null)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- // We don't really need to search line by line, I'm doing this so that it's possible/easy to debug.
- var lines = result.Output.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
- for (var i = 0; i < lines.Length; i++)
- {
- var line = lines[i];
- var match = ErrorRegex.Match(line);
- if (match.Success)
- {
- if (match.Groups["errorcode"].Value != errorCode)
- {
- continue;
- }
-
- if (location != null && match.Groups["location"].Value.Trim() != location)
- {
- continue;
- }
-
- // This is a match
- return;
- }
- }
-
- throw new BuildErrorMissingException(result, errorCode, location);
- }
-
- public static void BuildWarning(MSBuildResult result, string errorCode, string location = null)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- // We don't really need to search line by line, I'm doing this so that it's possible/easy to debug.
- foreach (var (_, match) in GetBuildWarnings(result))
- {
- if (match.Groups["errorcode"].Value != errorCode)
- {
- continue;
- }
-
- if (location != null && match.Groups["location"].Value.Trim() != location)
- {
- continue;
- }
-
- // This is a match
- return;
- }
-
- throw new BuildErrorMissingException(result, errorCode, location);
- }
-
- private static IEnumerable<(string line, Match match)> GetBuildWarnings(MSBuildResult result)
- {
- var lines = result.Output.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
- for (var i = 0; i < lines.Length; i++)
- {
- var line = lines[i];
- var match = WarningRegex.Match(line);
- if (match.Success)
- {
- yield return (line, match);
- }
- }
- }
-
- public static void BuildFailed(MSBuildResult result)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- };
-
- if (result.ExitCode == 0)
- {
- throw new BuildPassedException(result);
- }
- }
-
- public static void BuildOutputContainsLine(MSBuildResult result, string match)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- if (match == null)
- {
- throw new ArgumentNullException(nameof(match));
- }
-
- // We don't really need to search line by line, I'm doing this so that it's possible/easy to debug.
- var lines = result.Output.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
- for (var i = 0; i < lines.Length; i++)
- {
- var line = lines[i].Trim();
- if (line == match)
- {
- return;
- }
- }
-
- throw new BuildOutputMissingException(result, match);
- }
-
- public static void BuildOutputDoesNotContainLine(MSBuildResult result, string match)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- if (match == null)
- {
- throw new ArgumentNullException(nameof(match));
- }
-
- // We don't really need to search line by line, I'm doing this so that it's possible/easy to debug.
- var lines = result.Output.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
- for (var i = 0; i < lines.Length; i++)
- {
- var line = lines[i].Trim();
- if (line == match)
- {
- throw new BuildOutputContainsLineException(result, match);
- }
- }
- }
-
- public static void FileContains(MSBuildResult result, string filePath, string match)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- filePath = Path.Combine(result.Project.DirectoryPath, filePath);
- FileExists(result, filePath);
-
- var text = File.ReadAllText(filePath);
- if (text.Contains(match))
- {
- return;
- }
-
- throw new FileContentMissingException(result, filePath, File.ReadAllText(filePath), match);
- }
-
- public static void FileDoesNotContain(MSBuildResult result, string filePath, string match)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- filePath = Path.Combine(result.Project.DirectoryPath, filePath);
- FileExists(result, filePath);
-
- var text = File.ReadAllText(filePath);
- if (text.Contains(match))
- {
- throw new FileContentFoundException(result, filePath, File.ReadAllText(filePath), match);
- }
- }
-
- public static void FileContentEquals(MSBuildResult result, string filePath, string expected)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- filePath = Path.Combine(result.Project.DirectoryPath, filePath);
- FileExists(result, filePath);
-
- var actual = File.ReadAllText(filePath);
- if (!actual.Equals(expected, StringComparison.Ordinal))
- {
- throw new FileContentNotEqualException(result, filePath, expected, actual);
- }
- }
-
- public static void FileHashEquals(MSBuildResult result, string filePath, string expectedSha256Base64)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- filePath = Path.Combine(result.Project.DirectoryPath, filePath);
- FileExists(result, filePath);
-
- var actual = File.ReadAllBytes(filePath);
- using var algorithm = SHA256.Create();
- var actualSha256 = algorithm.ComputeHash(actual);
- var actualSha256Base64 = Convert.ToBase64String(actualSha256);
- Assert.Equal(expectedSha256Base64, actualSha256Base64);
- }
-
- public static void FileEquals(MSBuildResult result, string expected, string actual)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- expected = Path.Combine(result.Project.DirectoryPath, expected);
- actual = Path.Combine(result.Project.DirectoryPath, actual);
- FileExists(result, expected);
- FileExists(result, actual);
-
- if (!Enumerable.SequenceEqual(File.ReadAllBytes(expected), File.ReadAllBytes(actual)))
- {
- throw new FilesNotEqualException(result, expected, actual);
- }
- }
-
- public static void FileContainsLine(MSBuildResult result, string filePath, string match)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- filePath = Path.Combine(result.Project.DirectoryPath, filePath);
- FileExists(result, filePath);
-
- var lines = File.ReadAllLines(filePath);
- for (var i = 0; i < lines.Length; i++)
- {
- var line = lines[i].Trim();
- if (line == match)
- {
- return;
- }
- }
-
- throw new FileContentMissingException(result, filePath, File.ReadAllText(filePath), match);
- }
-
- public static void FileDoesNotContainLine(MSBuildResult result, string filePath, string match)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- filePath = Path.Combine(result.Project.DirectoryPath, filePath);
- FileExists(result, filePath);
-
- var lines = File.ReadAllLines(filePath);
- for (var i = 0; i < lines.Length; i++)
- {
- var line = lines[i].Trim();
- if (line == match)
- {
- throw new FileContentFoundException(result, filePath, File.ReadAllText(filePath), match);
- }
- }
- }
-
- public static string FileExists(MSBuildResult result, params string[] paths)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- var filePath = Path.Combine(result.Project.DirectoryPath, Path.Combine(paths));
- if (!File.Exists(filePath))
- {
- throw new FileMissingException(result, filePath);
- }
-
- return filePath;
- }
-
- public static void FileCountEquals(MSBuildResult result, int expected, string directoryPath, string searchPattern, SearchOption searchOption = SearchOption.AllDirectories)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- if (directoryPath == null)
- {
- throw new ArgumentNullException(nameof(directoryPath));
- }
-
- if (searchPattern == null)
- {
- throw new ArgumentNullException(nameof(searchPattern));
- }
-
- directoryPath = Path.Combine(result.Project.DirectoryPath, directoryPath);
-
- if (Directory.Exists(directoryPath))
- {
- var files = Directory.GetFiles(directoryPath, searchPattern, searchOption);
- if (files.Length != expected)
- {
- throw new FileCountException(result, expected, directoryPath, searchPattern, files);
- }
- }
- else if (expected > 0)
- {
- // directory doesn't exist, that's OK if we expected to find nothing.
- throw new FileCountException(result, expected, directoryPath, searchPattern, Array.Empty<string>());
- }
- }
-
- public static void FileDoesNotExist(MSBuildResult result, params string[] paths)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- var filePath = Path.Combine(result.Project.DirectoryPath, Path.Combine(paths));
- if (File.Exists(filePath))
- {
- throw new FileFoundException(result, filePath);
- }
- }
-
- public static void NuspecContains(MSBuildResult result, string nuspecPath, string expected)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- if (nuspecPath == null)
- {
- throw new ArgumentNullException(nameof(nuspecPath));
- }
-
- if (expected == null)
- {
- throw new ArgumentNullException(nameof(expected));
- }
-
- nuspecPath = Path.Combine(result.Project.DirectoryPath, nuspecPath);
- FileExists(result, nuspecPath);
-
- var content = File.ReadAllText(nuspecPath);
- if (!content.Contains(expected))
- {
- throw new NuspecException(result, nuspecPath, content, expected);
- }
- }
-
- public static void NuspecDoesNotContain(MSBuildResult result, string nuspecPath, string expected)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- if (nuspecPath == null)
- {
- throw new ArgumentNullException(nameof(nuspecPath));
- }
-
- if (expected == null)
- {
- throw new ArgumentNullException(nameof(expected));
- }
-
- nuspecPath = Path.Combine(result.Project.DirectoryPath, nuspecPath);
- FileExists(result, nuspecPath);
-
- var content = File.ReadAllText(nuspecPath);
- if (content.Contains(expected))
- {
- throw new NuspecFoundException(result, nuspecPath, content, expected);
- }
- }
-
- // This method extracts the nupkg to a fixed directory path. To avoid the extra work of
- // cleaning up after each invocation, this method accepts multiple files.
- public static void NupkgContains(MSBuildResult result, string nupkgPath, params string[] filePaths)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- if (nupkgPath == null)
- {
- throw new ArgumentNullException(nameof(nupkgPath));
- }
-
- if (filePaths == null)
- {
- throw new ArgumentNullException(nameof(filePaths));
- }
-
- nupkgPath = Path.Combine(result.Project.DirectoryPath, nupkgPath);
- FileExists(result, nupkgPath);
-
- var unzipped = Path.Combine(result.Project.DirectoryPath, Path.GetFileNameWithoutExtension(nupkgPath));
- ZipFile.ExtractToDirectory(nupkgPath, unzipped);
-
- foreach (var filePath in filePaths)
- {
- if (!File.Exists(Path.Combine(unzipped, filePath)))
- {
- throw new NupkgFileMissingException(result, nupkgPath, filePath);
- }
- }
- }
-
- // This method extracts the nupkg to a fixed directory path. To avoid the extra work of
- // cleaning up after each invocation, this method accepts multiple files.
- public static void NupkgDoesNotContain(MSBuildResult result, string nupkgPath, params string[] filePaths)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- if (nupkgPath == null)
- {
- throw new ArgumentNullException(nameof(nupkgPath));
- }
-
- if (filePaths == null)
- {
- throw new ArgumentNullException(nameof(filePaths));
- }
-
- nupkgPath = Path.Combine(result.Project.DirectoryPath, nupkgPath);
- FileExists(result, nupkgPath);
-
- var unzipped = Path.Combine(result.Project.DirectoryPath, Path.GetFileNameWithoutExtension(nupkgPath));
- ZipFile.ExtractToDirectory(nupkgPath, unzipped);
-
- foreach (var filePath in filePaths)
- {
- if (File.Exists(Path.Combine(unzipped, filePath)))
- {
- throw new NupkgFileFoundException(result, nupkgPath, filePath);
- }
- }
- }
-
- public static void AssemblyContainsType(MSBuildResult result, string assemblyPath, string fullTypeName)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- assemblyPath = Path.Combine(result.Project.DirectoryPath, Path.Combine(assemblyPath));
-
- var typeNames = GetDeclaredTypeNames(assemblyPath);
- Assert.Contains(fullTypeName, typeNames);
- }
-
- public static void AssemblyDoesNotContainType(MSBuildResult result, string assemblyPath, string fullTypeName)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- assemblyPath = Path.Combine(result.Project.DirectoryPath, Path.Combine(assemblyPath));
-
- var typeNames = GetDeclaredTypeNames(assemblyPath);
- Assert.DoesNotContain(fullTypeName, typeNames);
- }
-
- private static IEnumerable<string> GetDeclaredTypeNames(string assemblyPath)
- {
- using (var file = File.OpenRead(assemblyPath))
- {
- using var peReader = new PEReader(file);
- var metadataReader = peReader.GetMetadataReader();
- return metadataReader.TypeDefinitions.Where(t => !t.IsNil).Select(t =>
- {
- var type = metadataReader.GetTypeDefinition(t);
- return metadataReader.GetString(type.Namespace) + "." + metadataReader.GetString(type.Name);
- }).ToArray();
- }
- }
-
- public static void AssemblyContainsResource(MSBuildResult result, string assemblyPath, string resourceName)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- assemblyPath = Path.Combine(result.Project.DirectoryPath, Path.Combine(assemblyPath));
-
- var resources = GetAssemblyResourceNames(assemblyPath);
- Assert.Contains(resourceName, resources);
- }
-
- public static void AssemblyDoesNotContainResource(MSBuildResult result, string assemblyPath, string resourceName)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- assemblyPath = Path.Combine(result.Project.DirectoryPath, Path.Combine(assemblyPath));
-
- var resources = GetAssemblyResourceNames(assemblyPath);
- Assert.DoesNotContain(resourceName, resources);
- }
-
- private static IEnumerable<string> GetAssemblyResourceNames(string assemblyPath)
- {
- using var file = File.OpenRead(assemblyPath);
- using var peReader = new PEReader(file);
- var metadataReader = peReader.GetMetadataReader();
- return metadataReader.ManifestResources.Where(r => !r.IsNil).Select(r =>
- {
- var resource = metadataReader.GetManifestResource(r);
- return metadataReader.GetString(resource.Name);
- }).ToArray();
- }
-
- public static void AssemblyHasAttribute(MSBuildResult result, string assemblyPath, string fullTypeName)
- {
- if (result == null)
- {
- throw new ArgumentNullException(nameof(result));
- }
-
- assemblyPath = Path.Combine(result.Project.DirectoryPath, Path.Combine(assemblyPath));
-
- var typeNames = GetAssemblyAttributes(assemblyPath);
- Assert.Contains(fullTypeName, typeNames);
- }
-
- private static IEnumerable<string> GetAssemblyAttributes(string assemblyPath)
- {
- using (var file = File.OpenRead(assemblyPath))
- {
- var peReader = new PEReader(file);
- var metadataReader = peReader.GetMetadataReader();
- return metadataReader.CustomAttributes.Where(t => !t.IsNil).Select(t =>
- {
- var attribute = metadataReader.GetCustomAttribute(t);
- var constructor = metadataReader.GetMemberReference((MemberReferenceHandle)attribute.Constructor);
- var type = metadataReader.GetTypeReference((TypeReferenceHandle)constructor.Parent);
-
- return metadataReader.GetString(type.Namespace) + "." + metadataReader.GetString(type.Name);
- }).ToArray();
- }
- }
-
- private abstract class MSBuildXunitException : Xunit.Sdk.XunitException
- {
- protected MSBuildXunitException(MSBuildResult result)
- {
- Result = result;
- }
-
- protected abstract string Heading { get; }
-
- public MSBuildResult Result { get; }
-
- public override string Message
- {
- get
- {
- var message = new StringBuilder();
- message.AppendLine(Heading);
- message.Append(Result.FileName);
- message.Append(" ");
- message.Append(Result.Arguments);
- message.AppendLine();
- message.AppendLine();
- message.Append(Result.Output);
- message.AppendLine();
- message.Append("Exit Code:");
- message.Append(Result.ExitCode);
- return message.ToString();
- }
- }
- }
-
- private class BuildErrorMissingException : MSBuildXunitException
- {
- public BuildErrorMissingException(MSBuildResult result, string errorCode, string location)
- : base(result)
- {
- ErrorCode = errorCode;
- Location = location;
- }
-
- public string ErrorCode { get; }
-
- public string Location { get; }
-
- protected override string Heading
- {
- get
- {
- return
- $"Error code '{ErrorCode}' was not found." + Environment.NewLine +
- $"Looking for '{Location ?? ".*"}: error {ErrorCode}: .*'";
- }
- }
- }
-
- private class BuildFailedException : MSBuildXunitException
- {
- public BuildFailedException(MSBuildResult result)
- : base(result)
- {
- }
-
- protected override string Heading => "Build failed.";
- }
-
- private class BuildWarningsException : MSBuildXunitException
- {
- public BuildWarningsException(MSBuildResult result, IEnumerable<string> warnings)
- : base(result)
- {
- Warnings = warnings.ToList();
- }
-
- public List<string> Warnings { get; }
-
- protected override string Heading => "Build contains unexpected warnings: " + string.Join(Environment.NewLine, Warnings);
- }
-
- private class BuildPassedException : MSBuildXunitException
- {
- public BuildPassedException(MSBuildResult result)
- : base(result)
- {
- }
-
- protected override string Heading => "Build should have failed, but it passed.";
- }
-
- private class BuildOutputMissingException : MSBuildXunitException
- {
- public BuildOutputMissingException(MSBuildResult result, string match)
- : base(result)
- {
- Match = match;
- }
-
- public string Match { get; }
-
- protected override string Heading => $"Build did not contain the line: '{Match}'.";
- }
-
- private class BuildOutputContainsLineException : MSBuildXunitException
- {
- public BuildOutputContainsLineException(MSBuildResult result, string match)
- : base(result)
- {
- Match = match;
- }
-
- public string Match { get; }
-
- protected override string Heading => $"Build output contains the line: '{Match}'.";
- }
-
- private class FileContentFoundException : MSBuildXunitException
- {
- public FileContentFoundException(MSBuildResult result, string filePath, string content, string match)
- : base(result)
- {
- FilePath = filePath;
- Content = content;
- Match = match;
- }
-
- public string Content { get; }
-
- public string FilePath { get; }
-
- public string Match { get; }
-
- protected override string Heading
- {
- get
- {
- var builder = new StringBuilder();
- builder.AppendFormat("File content of '{0}' should not contain line: '{1}'.", FilePath, Match);
- builder.AppendLine();
- builder.AppendLine();
- builder.AppendLine(Content);
- return builder.ToString();
- }
- }
- }
-
- private class FileContentMissingException : MSBuildXunitException
- {
- public FileContentMissingException(MSBuildResult result, string filePath, string content, string match)
- : base(result)
- {
- FilePath = filePath;
- Content = content;
- Match = match;
- }
-
- public string Content { get; }
-
- public string FilePath { get; }
-
- public string Match { get; }
-
- protected override string Heading
- {
- get
- {
- var builder = new StringBuilder();
- builder.AppendFormat("File content of '{0}' did not contain the line: '{1}'.", FilePath, Match);
- builder.AppendLine();
- builder.AppendLine();
- builder.AppendLine(Content);
- return builder.ToString();
- }
- }
- }
-
- private class FileContentNotEqualException : MSBuildXunitException
- {
- public FileContentNotEqualException(MSBuildResult result, string filePath, string expected, string actual)
- : base(result)
- {
- FilePath = filePath;
- Expected = expected;
- Actual = actual;
- }
-
- public string Actual { get; }
-
- public string FilePath { get; }
-
- public string Expected { get; }
-
- protected override string Heading
- {
- get
- {
- var builder = new StringBuilder();
- builder.AppendFormat("File content of '{0}' did not match the expected content: '{1}'.", FilePath, Expected);
- builder.AppendLine();
- builder.AppendLine();
- builder.AppendLine(Actual);
- return builder.ToString();
- }
- }
- }
-
- private class FilesNotEqualException : MSBuildXunitException
- {
- public FilesNotEqualException(MSBuildResult result, string expected, string actual)
- : base(result)
- {
- Expected = expected;
- Actual = actual;
- }
-
- public string Actual { get; }
-
- public string Expected { get; }
-
- protected override string Heading
- {
- get
- {
- var builder = new StringBuilder();
- builder.AppendFormat("File content of '{0}' did not match the contents of '{1}'.", Expected, Actual);
- builder.AppendLine();
- builder.AppendLine();
- builder.AppendLine(Actual);
- return builder.ToString();
- }
- }
- }
-
- private class FileMissingException : MSBuildXunitException
- {
- public FileMissingException(MSBuildResult result, string filePath)
- : base(result)
- {
- FilePath = filePath;
- }
-
- public string FilePath { get; }
-
- protected override string Heading => $"File: '{FilePath}' was not found.";
- }
-
- private class FileCountException : MSBuildXunitException
- {
- public FileCountException(MSBuildResult result, int expected, string directoryPath, string searchPattern, string[] files)
- : base(result)
- {
- Expected = expected;
- DirectoryPath = directoryPath;
- SearchPattern = searchPattern;
- Files = files;
- }
-
- public string DirectoryPath { get; }
-
- public int Expected { get; }
-
- public string[] Files { get; }
-
- public string SearchPattern { get; }
-
- protected override string Heading
- {
- get
- {
- var heading = new StringBuilder();
- heading.AppendLine($"Expected {Expected} files matching {SearchPattern} in {DirectoryPath}, found {Files.Length}.");
-
- if (Files.Length > 0)
- {
- heading.AppendLine("Files:");
-
- foreach (var file in Files)
- {
- heading.Append("\t");
- heading.Append(file);
- }
-
- heading.AppendLine();
- }
-
- return heading.ToString();
- }
- }
- }
-
- private class FileFoundException : MSBuildXunitException
- {
- public FileFoundException(MSBuildResult result, string filePath)
- : base(result)
- {
- FilePath = filePath;
- }
-
- public string FilePath { get; }
-
- protected override string Heading => $"File: '{FilePath}' was found, but should not exist.";
- }
-
- private class NuspecException : MSBuildXunitException
- {
- public NuspecException(MSBuildResult result, string filePath, string content, string expected)
- : base(result)
- {
- FilePath = filePath;
- Content = content;
- Expected = expected;
- }
-
- public string Content { get; }
-
- public string Expected { get; }
-
- public string FilePath { get; }
-
- protected override string Heading
- {
- get
- {
- return
- $"nuspec: '{FilePath}' did not contain the expected content." + Environment.NewLine +
- Environment.NewLine +
- $"expected: {Expected}" + Environment.NewLine +
- Environment.NewLine +
- $"actual: {Content}";
- }
- }
- }
-
- private class NuspecFoundException : MSBuildXunitException
- {
- public NuspecFoundException(MSBuildResult result, string filePath, string content, string expected)
- : base(result)
- {
- FilePath = filePath;
- Content = content;
- Expected = expected;
- }
-
- public string Content { get; }
-
- public string Expected { get; }
-
- public string FilePath { get; }
-
- protected override string Heading
- {
- get
- {
- return
- $"nuspec: '{FilePath}' should not contain the content {Expected}." +
- Environment.NewLine +
- $"actual content: {Content}";
- }
- }
- }
-
- private class NupkgFileMissingException : MSBuildXunitException
- {
- public NupkgFileMissingException(MSBuildResult result, string nupkgPath, string filePath)
- : base(result)
- {
- NupkgPath = nupkgPath;
- FilePath = filePath;
- }
-
- public string FilePath { get; }
-
- public string NupkgPath { get; }
-
- protected override string Heading => $"File: '{FilePath}' was not found was not found in {NupkgPath}.";
- }
-
- private class NupkgFileFoundException : MSBuildXunitException
- {
- public NupkgFileFoundException(MSBuildResult result, string nupkgPath, string filePath)
- : base(result)
- {
- NupkgPath = nupkgPath;
- FilePath = filePath;
- }
-
- public string FilePath { get; }
-
- public string NupkgPath { get; }
-
- protected override string Heading => $"File: '{FilePath}' was found in {NupkgPath}.";
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildCompressionTests.cs b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildCompressionTests.cs
deleted file mode 100644
index 397d32bd61..0000000000
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildCompressionTests.cs
+++ /dev/null
@@ -1,396 +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 System;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- public class BuildCompressionTests
- {
- [Fact]
- public async Task Build_WithLinkerAndCompression_IsIncremental()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- var result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- // Act
- var compressedFilesFolder = Path.Combine(project.IntermediateOutputDirectory, "compressed");
- var thumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
-
- // Assert
- for (var i = 0; i < 3; i++)
- {
- result = await MSBuildProcessManager.DotnetMSBuild(project);
- Assert.BuildPassed(result);
-
- var newThumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
- Assert.Equal(thumbPrint.Count, newThumbPrint.Count);
- for (var j = 0; j < thumbPrint.Count; j++)
- {
- Assert.Equal(thumbPrint[j], newThumbPrint[j]);
- }
- }
- }
-
- [Fact]
- public async Task Build_WithLinkerAndCompression_UpdatesFilesWhenSourcesChange()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- var result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- Assert.BuildPassed(result);
-
- var mainAppDll = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll");
- var mainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll);
- var mainAppCompressedDll = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll.gz");
- var mainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);
-
- var blazorBootJson = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
- var blazorBootJsonThumbPrint = FileThumbPrint.Create(blazorBootJson);
- var blazorBootJsonCompressed = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json.gz");
- var blazorBootJsonCompressedThumbPrint = FileThumbPrint.Create(blazorBootJsonCompressed);
-
- // Act
- var programFile = Path.Combine(project.DirectoryPath, "Program.cs");
- var programFileContents = File.ReadAllText(programFile);
- File.WriteAllText(programFile, programFileContents.Replace("args", "arguments"));
- result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- // Assert
- Assert.BuildPassed(result);
- var newMainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll);
- var newMainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);
- var newBlazorBootJsonThumbPrint = FileThumbPrint.Create(blazorBootJson);
- var newBlazorBootJsonCompressedThumbPrint = FileThumbPrint.Create(blazorBootJsonCompressed);
-
- Assert.NotEqual(mainAppDllThumbPrint, newMainAppDllThumbPrint);
- Assert.NotEqual(mainAppCompressedDllThumbPrint, newMainAppCompressedDllThumbPrint);
-
- Assert.NotEqual(blazorBootJsonThumbPrint, newBlazorBootJsonThumbPrint);
- Assert.NotEqual(blazorBootJsonCompressedThumbPrint, newBlazorBootJsonCompressedThumbPrint);
- }
-
- [Fact]
- public async Task Build_WithoutLinkerAndCompression_IsIncremental()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/p:BlazorWebAssemblyEnableLinking=false");
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- // Act
- var compressedFilesFolder = Path.Combine(project.IntermediateOutputDirectory, "compressed");
- var thumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
-
- // Assert
- for (var i = 0; i < 3; i++)
- {
- result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/p:BlazorWebAssemblyEnableLinking=false");
- Assert.BuildPassed(result);
-
- var newThumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
- Assert.Equal(thumbPrint.Count, newThumbPrint.Count);
- for (var j = 0; j < thumbPrint.Count; j++)
- {
- Assert.Equal(thumbPrint[j], newThumbPrint[j]);
- }
- }
- }
-
- [Fact]
- public async Task Build_WithoutLinkerAndCompression_UpdatesFilesWhenSourcesChange()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/p:BlazorWebAssemblyEnableLinking=false");
-
- // Act
- var mainAppDll = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll");
- var mainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll);
-
- var mainAppCompressedDll = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll.gz");
- var mainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);
-
- var programFile = Path.Combine(project.DirectoryPath, "Program.cs");
- var programFileContents = File.ReadAllText(programFile);
- File.WriteAllText(programFile, programFileContents.Replace("args", "arguments"));
-
- // Assert
- result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/p:BlazorWebAssemblyEnableLinking=false");
- Assert.BuildPassed(result);
- var newMainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll);
- var newMainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);
-
- Assert.NotEqual(mainAppDllThumbPrint, newMainAppDllThumbPrint);
- Assert.NotEqual(mainAppCompressedDllThumbPrint, newMainAppCompressedDllThumbPrint);
- }
-
- [Fact]
- public async Task Build_CompressesAllFrameworkFiles()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- var result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- var extensions = new[] { ".dll", ".js", ".pdb", ".wasm", ".map", ".json", ".dat" };
- // Act
- var compressedFilesPath = Path.Combine(
- project.DirectoryPath,
- project.IntermediateOutputDirectory,
- "compressed",
- "_framework");
- var compressedFiles = Directory.EnumerateFiles(
- compressedFilesPath,
- "*",
- SearchOption.AllDirectories)
- .Where(f => Path.GetExtension(f) == ".gz")
- .Select(f => Path.GetRelativePath(compressedFilesPath, f[0..^3]))
- .OrderBy(f => f)
- .ToArray();
-
- var frameworkFilesPath = Path.Combine(
- project.DirectoryPath,
- project.BuildOutputDirectory,
- "wwwroot",
- "_framework");
- var frameworkFiles = Directory.EnumerateFiles(
- frameworkFilesPath,
- "*",
- SearchOption.AllDirectories)
- .Where(f => extensions.Contains(Path.GetExtension(f)))
- .Select(f => Path.GetRelativePath(frameworkFilesPath, f))
- .OrderBy(f => f)
- .ToArray();
-
- Assert.Equal(frameworkFiles.Length, compressedFiles.Length);
- Assert.Equal(frameworkFiles, compressedFiles);
-
- var brotliFiles = Directory.EnumerateFiles(
- compressedFilesPath,
- "*",
- SearchOption.AllDirectories)
- .Where(f => Path.GetExtension(f) == ".br")
- .Select(f => Path.GetRelativePath(compressedFilesPath, f[0..^3]))
- .OrderBy(f => f)
- .ToArray();
-
- // We don't compress things with brotli at build time
- Assert.Empty(brotliFiles);
- }
-
- [Fact]
- public async Task Build_DisabledCompression_DoesNotCompressFiles()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
-
- // Act
- var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/p:BlazorEnableCompression=false");
-
- //Assert
- Assert.BuildPassed(result);
-
- var compressedFilesPath = Path.Combine(
- project.DirectoryPath,
- project.IntermediateOutputDirectory,
- "compressed");
-
- Assert.False(Directory.Exists(compressedFilesPath));
- }
-
- [Fact]
- public async Task Publish_WithLinkerAndCompression_UpdatesFilesWhenSourcesChange()
- {
- // Arrange
- using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary" });
- project.TargetFramework = TestFacts.DefaultNetCoreTargetFramework;
- var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish");
-
- Assert.BuildPassed(result);
-
- // Act
- var mainAppDll = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll");
- var mainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll);
- var mainAppCompressedDll = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll.br");
- var mainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);
-
- var blazorBootJson = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
- var blazorBootJsonThumbPrint = FileThumbPrint.Create(blazorBootJson);
- var blazorBootJsonCompressed = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazor.boot.json.br");
- var blazorBootJsonCompressedThumbPrint = FileThumbPrint.Create(blazorBootJsonCompressed);
-
- var programFile = Path.Combine(project.DirectoryPath, "..", "standalone", "Program.cs");
- var programFileContents = File.ReadAllText(programFile);
- File.WriteAllText(programFile, programFileContents.Replace("args", "arguments"));
-
- // Assert
- result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish");
- Assert.BuildPassed(result);
- var newMainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll);
- var newMainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);
- var newBlazorBootJsonThumbPrint = FileThumbPrint.Create(blazorBootJson);
- var newBlazorBootJsonCompressedThumbPrint = FileThumbPrint.Create(blazorBootJsonCompressed);
-
- Assert.NotEqual(mainAppDllThumbPrint, newMainAppDllThumbPrint);
- Assert.NotEqual(mainAppCompressedDllThumbPrint, newMainAppCompressedDllThumbPrint);
-
- Assert.NotEqual(blazorBootJsonThumbPrint, newBlazorBootJsonThumbPrint);
- Assert.NotEqual(blazorBootJsonCompressedThumbPrint, newBlazorBootJsonCompressedThumbPrint);
- }
-
- [Fact]
- public async Task Publish_WithoutLinkerAndCompression_UpdatesFilesWhenSourcesChange()
- {
- // Arrange
- using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary" });
- project.TargetFramework = TestFacts.DefaultNetCoreTargetFramework;
- var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish", args: "/p:BlazorWebAssemblyEnableLinking=false");
-
- Assert.BuildPassed(result);
-
- // Act
- var mainAppDll = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll");
- var mainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll);
-
- var mainAppCompressedDll = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll.br");
- var mainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);
-
- var programFile = Path.Combine(project.DirectoryPath, "..", "standalone", "Program.cs");
- var programFileContents = File.ReadAllText(programFile);
- File.WriteAllText(programFile, programFileContents.Replace("args", "arguments"));
-
- // Assert
- result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish", args: "/p:BlazorWebAssemblyEnableLinking=false");
- Assert.BuildPassed(result);
- var newMainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll);
- var newMainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);
-
- Assert.NotEqual(mainAppDllThumbPrint, newMainAppDllThumbPrint);
- Assert.NotEqual(mainAppCompressedDllThumbPrint, newMainAppCompressedDllThumbPrint);
- }
-
- [Fact]
- public async Task Publish_WithLinkerAndCompression_IsIncremental()
- {
- // Arrange
- using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary" });
- var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish");
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- // Act
- var compressedFilesFolder = Path.Combine("..", "standalone", project.IntermediateOutputDirectory, "compressed");
- var thumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
-
- // Assert
- for (var i = 0; i < 3; i++)
- {
- result = await MSBuildProcessManager.DotnetMSBuild(project);
- Assert.BuildPassed(result);
-
- var newThumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
- Assert.Equal(thumbPrint.Count, newThumbPrint.Count);
- for (var j = 0; j < thumbPrint.Count; j++)
- {
- Assert.Equal(thumbPrint[j], newThumbPrint[j]);
- }
- }
- }
-
- [Fact]
- public async Task Publish_WithoutLinkerAndCompression_IsIncremental()
- {
- // Arrange
- using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary" });
- var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish", args: "/p:BlazorWebAssemblyEnableLinking=false");
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- // Act
- var compressedFilesFolder = Path.Combine("..", "standalone", project.IntermediateOutputDirectory, "compressed");
- var thumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
-
- // Assert
- for (var i = 0; i < 3; i++)
- {
- result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/p:BlazorWebAssemblyEnableLinking=false");
- Assert.BuildPassed(result);
-
- var newThumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
- Assert.Equal(thumbPrint.Count, newThumbPrint.Count);
- for (var j = 0; j < thumbPrint.Count; j++)
- {
- Assert.Equal(thumbPrint[j], newThumbPrint[j]);
- }
- }
- }
-
- [Fact]
- public async Task Publish_CompressesAllFrameworkFiles()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish");
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- var extensions = new[] { ".dll", ".js", ".pdb", ".wasm", ".map", ".json", ".dat" };
- // Act
- var compressedFilesPath = Path.Combine(
- project.DirectoryPath,
- "..",
- "standalone",
- project.IntermediateOutputDirectory,
- "compressed",
- "_framework");
- var compressedFiles = Directory.EnumerateFiles(
- compressedFilesPath,
- "*",
- SearchOption.AllDirectories)
- .Where(f => Path.GetExtension(f) == ".br")
- .Select(f => Path.GetRelativePath(compressedFilesPath, f[0..^3]))
- .OrderBy(f => f)
- .ToArray();
-
- var frameworkFilesPath = Path.Combine(
- project.DirectoryPath,
- project.BuildOutputDirectory,
- "wwwroot",
- "_framework");
- var frameworkFiles = Directory.EnumerateFiles(
- frameworkFilesPath,
- "*",
- SearchOption.AllDirectories)
- .Where(f => extensions.Contains(Path.GetExtension(f)))
- .Select(f => Path.GetRelativePath(frameworkFilesPath, f))
- .OrderBy(f => f)
- .ToArray();
-
- Assert.Equal(frameworkFiles.Length, compressedFiles.Length);
- Assert.Equal(frameworkFiles, compressedFiles);
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildIntegrationTest.cs b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildIntegrationTest.cs
deleted file mode 100644
index c9184b649d..0000000000
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildIntegrationTest.cs
+++ /dev/null
@@ -1,361 +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 System.IO;
-using System.Text.Json;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Testing;
-using Xunit;
-using static Microsoft.AspNetCore.Components.WebAssembly.Build.WebAssemblyRuntimePackage;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- public class BuildIntegrationTest
- {
- [Fact]
- public async Task Build_WithDefaultSettings_Works()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- project.Configuration = "Debug";
- var result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.webassembly.js");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", "dotnet.wasm");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", DotNetJsFileName);
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", "dotnet.timezones.dat");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "RazorClassLibrary.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.pdb");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "RazorClassLibrary.pdb");
-
- var staticWebAssets = Assert.FileExists(result, buildOutputDirectory, "standalone.StaticWebAssets.xml");
- Assert.FileContains(result, staticWebAssets, Path.Combine("netstandard2.1", "wwwroot"));
- }
-
- [Fact]
- public async Task Build_InRelease_Works()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- project.Configuration = "Release";
- var result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.webassembly.js");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", "dotnet.wasm");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", DotNetJsFileName);
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", "dotnet.timezones.dat");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "RazorClassLibrary.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
- Assert.FileDoesNotExist(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.pdb");
- Assert.FileDoesNotExist(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "RazorClassLibrary.pdb");
-
- var staticWebAssets = Assert.FileExists(result, buildOutputDirectory, "standalone.StaticWebAssets.xml");
- Assert.FileContains(result, staticWebAssets, Path.Combine("netstandard2.1", "wwwroot"));
- }
-
- [Fact]
- public async Task Build_ProducesBootJsonDataWithExpectedContent()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- project.Configuration = "Debug";
- var result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- var bootJsonPath = Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
- var bootJsonData = ReadBootJsonData(result, bootJsonPath);
-
- var runtime = bootJsonData.resources.runtime.Keys;
- Assert.Contains(DotNetJsFileName, runtime);
- Assert.Contains("dotnet.wasm", runtime);
- Assert.Contains("dotnet.timezones.dat", runtime);
-
- var assemblies = bootJsonData.resources.assembly.Keys;
- Assert.Contains("standalone.dll", assemblies);
- Assert.Contains("RazorClassLibrary.dll", assemblies);
- Assert.Contains("Microsoft.Extensions.Logging.Abstractions.dll", assemblies);
-
- var pdb = bootJsonData.resources.pdb.Keys;
- Assert.Contains("standalone.pdb", pdb);
- Assert.Contains("RazorClassLibrary.pdb", pdb);
-
- Assert.Null(bootJsonData.resources.satelliteResources);
- }
-
- [Fact]
- public async Task Build_InRelease_ProducesBootJsonDataWithExpectedContent()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- project.Configuration = "Release";
- var result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- var bootJsonPath = Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
- var bootJsonData = ReadBootJsonData(result, bootJsonPath);
-
- var runtime = bootJsonData.resources.runtime.Keys;
- Assert.Contains(DotNetJsFileName, runtime);
- Assert.Contains("dotnet.wasm", runtime);
- Assert.Contains("dotnet.timezones.dat", runtime);
-
- var assemblies = bootJsonData.resources.assembly.Keys;
- Assert.Contains("standalone.dll", assemblies);
- Assert.Contains("RazorClassLibrary.dll", assemblies);
- Assert.Contains("Microsoft.Extensions.Logging.Abstractions.dll", assemblies);
-
- Assert.Null(bootJsonData.resources.pdb);
- Assert.Null(bootJsonData.resources.satelliteResources);
- }
-
- [Fact]
- public async Task Build_WithBlazorEnableTimeZoneSupportDisabled_DoesNotCopyTimeZoneInfo()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- project.Configuration = "Release";
- project.AddProjectFileContent(
-@"
-<PropertyGroup>
- <BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
-</PropertyGroup>");
-
- var result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- var bootJsonPath = Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
- var bootJsonData = ReadBootJsonData(result, bootJsonPath);
-
- var runtime = bootJsonData.resources.runtime.Keys;
- Assert.Contains("dotnet.wasm", runtime);
- Assert.DoesNotContain("dotnet.timezones.dat", runtime);
-
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", "dotnet.wasm");
- Assert.FileDoesNotExist(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", "dotnet.timezones.dat");
- }
-
- [Fact]
- public async Task Build_Hosted_Works()
- {
- // Arrange
- using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary", });
- project.TargetFramework = TestFacts.DefaultNetCoreTargetFramework;
- var result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- var path = Path.GetFullPath(Path.Combine(project.SolutionPath, "standalone", "bin", project.Configuration, "netstandard2.1", "standalone.dll"));
- Assert.FileDoesNotExist(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll");
-
- var staticWebAssets = Assert.FileExists(result, buildOutputDirectory, "blazorhosted.StaticWebAssets.xml");
- Assert.FileContains(result, staticWebAssets, Path.Combine("netstandard2.1", "wwwroot"));
- Assert.FileContains(result, staticWebAssets, Path.Combine("razorclasslibrary", "wwwroot"));
- Assert.FileContains(result, staticWebAssets, Path.Combine("standalone", "wwwroot"));
- }
-
- [Fact]
- public async Task Build_WithLinkOnBuildDisabled_Works()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- project.AddProjectFileContent(
-@"<PropertyGroup>
- <BlazorWebAssemblyEnableLinking>false</BlazorWebAssemblyEnableLinking>
-</PropertyGroup>");
-
- var result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.webassembly.js");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", "dotnet.wasm");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", DotNetJsFileName);
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", "dotnet.timezones.dat");
-
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
- }
-
- [Fact]
- [QuarantinedTest]
- public async Task Build_SatelliteAssembliesAreCopiedToBuildOutput()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
- project.AddProjectFileContent(
-@"
-<PropertyGroup>
- <DefineConstants>$(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies</DefineConstants>
-</PropertyGroup>
-<ItemGroup>
- <ProjectReference Include=""..\classlibrarywithsatelliteassemblies\classlibrarywithsatelliteassemblies.csproj"" />
-</ItemGroup>");
- var resxfileInProject = Path.Combine(project.DirectoryPath, "Resources.ja.resx.txt");
- File.Move(resxfileInProject, Path.Combine(project.DirectoryPath, "Resource.ja.resx"));
-
- var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/restore");
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "classlibrarywithsatelliteassemblies.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "Microsoft.CodeAnalysis.CSharp.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output.
-
- var bootJsonPath = Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
- Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\"");
- Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\"");
- }
-
- [Fact]
- public async Task Build_WithBlazorWebAssemblyEnableLinkingFalse_SatelliteAssembliesAreCopiedToBuildOutput()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
- project.AddProjectFileContent(
-@"
-<PropertyGroup>
- <BlazorWebAssemblyEnableLinking>false</BlazorWebAssemblyEnableLinking>
- <DefineConstants>$(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies</DefineConstants>
-</PropertyGroup>
-<ItemGroup>
- <ProjectReference Include=""..\classlibrarywithsatelliteassemblies\classlibrarywithsatelliteassemblies.csproj"" />
-</ItemGroup>");
-
- var resxfileInProject = Path.Combine(project.DirectoryPath, "Resources.ja.resx.txt");
- File.Move(resxfileInProject, Path.Combine(project.DirectoryPath, "Resource.ja.resx"));
-
- var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/restore");
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "classlibrarywithsatelliteassemblies.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "Microsoft.CodeAnalysis.CSharp.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output.
-
- var bootJson = ReadBootJsonData(result, Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json"));
-
- var satelliteResources = bootJson.resources.satelliteResources;
- Assert.NotNull(satelliteResources);
-
- Assert.Contains("es-ES", satelliteResources.Keys);
- Assert.Contains("es-ES/classlibrarywithsatelliteassemblies.resources.dll", satelliteResources["es-ES"].Keys);
- Assert.Contains("fr", satelliteResources.Keys);
- Assert.Contains("fr/Microsoft.CodeAnalysis.CSharp.resources.dll", satelliteResources["fr"].Keys);
- Assert.Contains("ja", satelliteResources.Keys);
- Assert.Contains("ja/standalone.resources.dll", satelliteResources["ja"].Keys);
- }
-
-
- [Fact]
- public async Task Build_WithI8NOption_CopiesI8NAssembliesWithoutLinkerEnabled()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- project.Configuration = "Debug";
- project.AddProjectFileContent(
-@"
-<PropertyGroup>
- <BlazorWebAssemblyI18NAssemblies>other</BlazorWebAssemblyI18NAssemblies>
-</PropertyGroup>");
-
- var result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "I18N.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "I18N.Other.dll");
- // When running without linker, we copy all I18N assemblies. Look for one additional
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "I18N.West.dll");
- }
-
- [Fact]
- public async Task Build_WithI8NOption_CopiesI8NAssembliesWithLinkerEnabled()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- project.Configuration = "Debug";
- project.AddProjectFileContent(
-@"
-<PropertyGroup>
- <BlazorWebAssemblyEnableLinking>true</BlazorWebAssemblyEnableLinking>
- <BlazorWebAssemblyI18NAssemblies>other</BlazorWebAssemblyI18NAssemblies>
-</PropertyGroup>");
-
- var result = await MSBuildProcessManager.DotnetMSBuild(project);
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "I18N.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "I18N.Other.dll");
- Assert.FileDoesNotExist(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "I18N.West.dll");
- }
-
- [Fact]
- public async Task Build_WithCustomOutputPath_Works()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
-
- project.AddDirectoryBuildContent(
-@"<PropertyGroup>
- <BaseOutputPath>$(MSBuildThisFileDirectory)build\bin\</BaseOutputPath>
- <BaseIntermediateOutputPath>$(MSBuildThisFileDirectory)build\obj\</BaseIntermediateOutputPath>
-</PropertyGroup>");
-
- var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/restore");
- Assert.BuildPassed(result);
-
- var compressedFilesPath = Path.Combine(
- project.DirectoryPath,
- "build",
- project.IntermediateOutputDirectory,
- "compressed");
-
- Assert.True(Directory.Exists(compressedFilesPath));
- }
-
- private static GenerateBlazorBootJson.BootJsonData ReadBootJsonData(MSBuildResult result, string path)
- {
- return JsonSerializer.Deserialize<GenerateBlazorBootJson.BootJsonData>(
- File.ReadAllText(Path.Combine(result.Project.DirectoryPath, path)),
- new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/FileThumbPrint.cs b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/FileThumbPrint.cs
deleted file mode 100644
index c5f210be52..0000000000
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/FileThumbPrint.cs
+++ /dev/null
@@ -1,74 +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 System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Security.Cryptography;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- internal class FileThumbPrint : IEquatable<FileThumbPrint>
- {
- private FileThumbPrint(string path, DateTime lastWriteTimeUtc, string hash)
- {
- FilePath = path;
- LastWriteTimeUtc = lastWriteTimeUtc;
- Hash = hash;
- }
-
- public string FilePath { get; }
-
- public DateTime LastWriteTimeUtc { get; }
-
- public string Hash { get; }
-
- public override string ToString()
- {
- return $"{Path.GetFileName(FilePath)}, {LastWriteTimeUtc.ToString("u")}, {Hash}";
- }
-
- /// <summary>
- /// Returns a list of thumbprints for all files (recursive) in the specified directory, sorted by file paths.
- /// </summary>
- public static List<FileThumbPrint> CreateFolderThumbprint(ProjectDirectory project, string directoryPath, params string[] filesToIgnore)
- {
- directoryPath = Path.Combine(project.DirectoryPath, directoryPath);
- var files = Directory.GetFiles(directoryPath).Where(p => !filesToIgnore.Contains(p));
- var thumbprintLookup = new List<FileThumbPrint>();
- foreach (var file in files)
- {
- var thumbprint = Create(file);
- thumbprintLookup.Add(thumbprint);
- }
-
- thumbprintLookup.Sort(Comparer<FileThumbPrint>.Create((a, b) => StringComparer.Ordinal.Compare(a.FilePath, b.FilePath)));
- return thumbprintLookup;
- }
-
- public static FileThumbPrint Create(string path)
- {
- byte[] hashBytes;
- using (var sha1 = SHA1.Create())
- using (var fileStream = File.OpenRead(path))
- {
- hashBytes = sha1.ComputeHash(fileStream);
- }
-
- var hash = Convert.ToBase64String(hashBytes);
- var lastWriteTimeUtc = File.GetLastWriteTimeUtc(path);
- return new FileThumbPrint(path, lastWriteTimeUtc, hash);
- }
-
- public bool Equals(FileThumbPrint other)
- {
- return
- string.Equals(FilePath, other.FilePath, StringComparison.Ordinal) &&
- LastWriteTimeUtc == other.LastWriteTimeUtc &&
- string.Equals(Hash, other.Hash, StringComparison.Ordinal);
- }
-
- public override int GetHashCode() => LastWriteTimeUtc.GetHashCode();
- }
-}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/MSBuildProcessManager.cs b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/MSBuildProcessManager.cs
deleted file mode 100644
index e1ee50af43..0000000000
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/MSBuildProcessManager.cs
+++ /dev/null
@@ -1,284 +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 System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.CommandLineUtils;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- internal static class MSBuildProcessManager
- {
- public static Task<MSBuildResult> DotnetMSBuild(
- ProjectDirectory project,
- string target = "Build",
- string args = null)
- {
- var buildArgumentList = new List<string>
- {
- // Disable node-reuse. We don't want msbuild processes to stick around
- // once the test is completed.
- "/nr:false",
-
- // Always generate a bin log for debugging purposes
- "/bl",
- };
-
- buildArgumentList.Add($"/t:{target}");
- buildArgumentList.Add($"/p:Configuration={project.Configuration}");
- buildArgumentList.Add($"/p:BlazorBuildConfiguration={ProjectDirectory.TestProjectConfiguration}");
- buildArgumentList.Add(args);
-
- var buildArguments = string.Join(" ", buildArgumentList);
-
- return MSBuildProcessManager.RunProcessAsync(project, buildArguments);
- }
-
- public static async Task<MSBuildResult> RunProcessAsync(
- ProjectDirectory project,
- string arguments,
- TimeSpan? timeout = null)
- {
- var processStartInfo = new ProcessStartInfo()
- {
- WorkingDirectory = project.DirectoryPath,
- UseShellExecute = false,
- RedirectStandardError = true,
- RedirectStandardOutput = true,
- };
-
- processStartInfo.FileName = DotNetMuxer.MuxerPathOrDefault();
- processStartInfo.Arguments = $"msbuild {arguments}";
-
- // Suppresses the 'Welcome to .NET Core!' output that times out tests and causes locked file issues.
- // When using dotnet we're not guarunteed to run in an environment where the dotnet.exe has had its first run experience already invoked.
- processStartInfo.EnvironmentVariables["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "true";
- processStartInfo.EnvironmentVariables["_BlazorWebAssemblyBuildTest_BrotliCompressionLevel_NoCompression"] = "1";
-
- var processResult = await RunProcessCoreAsync(processStartInfo, timeout);
-
- return new MSBuildResult(project, processResult.FileName, processResult.Arguments, processResult.ExitCode, processResult.Output);
- }
-
- internal static Task<ProcessResult> RunProcessCoreAsync(
- ProcessStartInfo processStartInfo,
- TimeSpan? timeout = null)
- {
- timeout = timeout ?? TimeSpan.FromSeconds(5 * 60);
-
- var process = new Process()
- {
- StartInfo = processStartInfo,
- EnableRaisingEvents = true,
- };
-
- var output = new StringBuilder();
- var outputLock = new object();
-
- var diagnostics = new StringBuilder();
- diagnostics.AppendLine("Process execution diagnostics:");
-
- process.ErrorDataReceived += Process_ErrorDataReceived;
- process.OutputDataReceived += Process_OutputDataReceived;
-
- process.Start();
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
-
- var timeoutTask = GetTimeoutForProcess(process, timeout, diagnostics);
-
- var waitTask = Task.Run(() =>
- {
- // We need to use two WaitForExit calls to ensure that all of the output/events are processed. Previously
- // this code used Process.Exited, which could result in us missing some output due to the ordering of
- // events.
- //
- // See the remarks here: https://msdn.microsoft.com/en-us/library/ty0d8k56(v=vs.110).aspx
- if (!process.WaitForExit(Int32.MaxValue))
- {
- // unreachable - the timeoutTask will kill the process before this happens.
- throw new TimeoutException();
- }
-
- process.WaitForExit();
-
-
- string outputString;
- lock (outputLock)
- {
- // This marks the end of the diagnostic info which we collect when something goes wrong.
- diagnostics.AppendLine("Process output:");
-
- // Expected output
- // Process execution diagnostics:
- // ...
- // Process output:
- outputString = diagnostics.ToString();
- outputString += output.ToString();
- }
-
- var result = new ProcessResult(process.StartInfo.FileName, process.StartInfo.Arguments, process.ExitCode, outputString);
- return result;
- });
-
- return Task.WhenAny<ProcessResult>(waitTask, timeoutTask).Unwrap();
-
- void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
- {
- lock (outputLock)
- {
- output.AppendLine(e.Data);
- }
- }
-
- void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
- {
- lock (outputLock)
- {
- output.AppendLine(e.Data);
- }
- }
-
- async Task<ProcessResult> GetTimeoutForProcess(Process process, TimeSpan? timeout, StringBuilder diagnostics)
- {
- await Task.Delay(timeout.Value);
-
- // Don't timeout during debug sessions
- while (Debugger.IsAttached)
- {
- Thread.Sleep(TimeSpan.FromSeconds(1));
- }
- if (!process.HasExited)
- {
- await CollectDumps(process, timeout, diagnostics);
-
- // This is a timeout.
- process.Kill();
- }
-
- throw new TimeoutException($"command '${process.StartInfo.FileName} {process.StartInfo.Arguments}' timed out after {timeout}. Output: {output.ToString()}");
- }
-
- static async Task CollectDumps(Process process, TimeSpan? timeout, StringBuilder diagnostics)
- {
- var procDumpProcess = await CaptureDump(process, timeout, diagnostics);
- var allDotNetProcesses = Process.GetProcessesByName("dotnet");
-
- var allDotNetChildProcessCandidates = allDotNetProcesses
- .Where(p => p.StartTime >= process.StartTime && p.Id != process.Id);
-
- if (!allDotNetChildProcessCandidates.Any())
- {
- diagnostics.AppendLine("Couldn't find any candidate child process.");
- foreach (var dotnetProcess in allDotNetProcesses)
- {
- diagnostics.AppendLine($"Found dotnet process with PID {dotnetProcess.Id} and start time {dotnetProcess.StartTime}.");
- }
- }
-
- foreach (var childProcess in allDotNetChildProcessCandidates)
- {
- diagnostics.AppendLine($"Found child process candidate '{childProcess.Id}'.");
- }
-
- var childrenProcessDumpProcesses = await Task.WhenAll(allDotNetChildProcessCandidates.Select(d => CaptureDump(d, timeout, diagnostics)));
- foreach (var childProcess in childrenProcessDumpProcesses)
- {
- if (childProcess != null && childProcess.HasExited)
- {
- diagnostics.AppendLine($"ProcDump failed to run for child dotnet process candidate '{process.Id}'.");
- childProcess.Kill();
- }
- }
-
- if (procDumpProcess != null && procDumpProcess.HasExited)
- {
- diagnostics.AppendLine($"ProcDump failed to run for '{process.Id}'.");
- procDumpProcess.Kill();
- }
- }
-
- static async Task<Process> CaptureDump(Process process, TimeSpan? timeout, StringBuilder diagnostics)
- {
- var metadataAttributes = Assembly.GetExecutingAssembly()
- .GetCustomAttributes<AssemblyMetadataAttribute>();
-
- var procDumpPath = metadataAttributes
- .SingleOrDefault(ama => ama.Key == "ProcDumpToolPath")?.Value;
-
- if (string.IsNullOrEmpty(procDumpPath))
- {
- diagnostics.AppendLine("ProcDumpPath not defined.");
- return null;
- }
- var procDumpExePath = Path.Combine(procDumpPath, "procdump.exe");
- if (!File.Exists(procDumpExePath))
- {
- diagnostics.AppendLine($"Can't find procdump.exe in '{procDumpPath}'.");
- return null;
- }
-
- var dumpDirectory = metadataAttributes
- .SingleOrDefault(ama => ama.Key == "ArtifactsLogDir")?.Value;
-
- if (string.IsNullOrEmpty(dumpDirectory))
- {
- diagnostics.AppendLine("ArtifactsLogDir not defined.");
- return null;
- }
-
- if (!Directory.Exists(dumpDirectory))
- {
- diagnostics.AppendLine($"'{dumpDirectory}' does not exist.");
- return null;
- }
-
- var procDumpPattern = Path.Combine(dumpDirectory, "HangingProcess_PROCESSNAME_PID_YYMMDD_HHMMSS.dmp");
- var procDumpStartInfo = new ProcessStartInfo(
- procDumpExePath,
- $"-accepteula -ma {process.Id} {procDumpPattern}")
- {
- CreateNoWindow = true,
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true
- };
-
- var procDumpProcess = Process.Start(procDumpStartInfo);
- var tcs = new TaskCompletionSource<object>();
-
- procDumpProcess.Exited += (s, a) => tcs.TrySetResult(null);
- procDumpProcess.EnableRaisingEvents = true;
-
- await Task.WhenAny(tcs.Task, Task.Delay(timeout ?? TimeSpan.FromSeconds(30)));
- return procDumpProcess;
- }
- }
-
- internal class ProcessResult
- {
- public ProcessResult(string fileName, string arguments, int exitCode, string output)
- {
- FileName = fileName;
- Arguments = arguments;
- ExitCode = exitCode;
- Output = output;
- }
-
- public string Arguments { get; }
-
- public string FileName { get; }
-
- public int ExitCode { get; }
-
- public string Output { get; }
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/MSBuildResult.cs b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/MSBuildResult.cs
deleted file mode 100644
index 4ad24e269d..0000000000
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/MSBuildResult.cs
+++ /dev/null
@@ -1,28 +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.WebAssembly.Build
-{
- internal class MSBuildResult
- {
- public MSBuildResult(ProjectDirectory project, string fileName, string arguments, int exitCode, string output)
- {
- Project = project;
- FileName = fileName;
- Arguments = arguments;
- ExitCode = exitCode;
- Output = output;
- }
-
- public ProjectDirectory Project { get; }
-
- public string Arguments { get; }
-
- public string FileName { get; }
-
- public int ExitCode { get; }
-
- public string Output { get; }
- }
-
-}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/ProjectDirectory.cs b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/ProjectDirectory.cs
deleted file mode 100644
index 97ad1e8bd3..0000000000
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/ProjectDirectory.cs
+++ /dev/null
@@ -1,233 +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 System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Threading;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- internal class ProjectDirectory : IDisposable
- {
- public bool PreserveWorkingDirectory { get; set; } = false;
-
- // Configuration the test project is building in.
- public static readonly string TestProjectConfiguration
-#if DEBUG
- = "Debug";
-#elif RELEASE
- = "Release";
-#else
-#error Configuration not supported
-#endif
-
- private static readonly string RepoRoot = GetTestAttribute("Testing.RepoRoot");
-
- public static ProjectDirectory Create(string projectName, string baseDirectory = "", string[] additionalProjects = null)
- {
- var destinationPath = Path.Combine(Path.GetTempPath(), "BlazorBuild", baseDirectory, Path.GetRandomFileName());
- Directory.CreateDirectory(destinationPath);
-
- try
- {
- if (Directory.EnumerateFiles(destinationPath).Any())
- {
- throw new InvalidOperationException($"{destinationPath} should be empty");
- }
-
- if (string.IsNullOrEmpty(RepoRoot))
- {
- throw new InvalidOperationException("RepoRoot was not specified.");
- }
-
- var testAppsRoot = Path.Combine(RepoRoot, "src", "Components", "WebAssembly", "Build", "testassets");
- foreach (var project in new string[] { projectName, }.Concat(additionalProjects ?? Array.Empty<string>()))
- {
- var projectRoot = Path.Combine(testAppsRoot, project);
- if (!Directory.Exists(projectRoot))
- {
- throw new InvalidOperationException($"Could not find project at '{projectRoot}'");
- }
-
- var projectDestination = Path.Combine(destinationPath, project);
- var projectDestinationDir = Directory.CreateDirectory(projectDestination);
- CopyDirectory(new DirectoryInfo(projectRoot), projectDestinationDir);
- SetupDirectoryBuildFiles(RepoRoot, testAppsRoot, projectDestination);
- }
-
- var directoryPath = Path.Combine(destinationPath, projectName);
- var projectPath = Path.Combine(directoryPath, projectName + ".csproj");
-
- CopyRepositoryAssets(destinationPath);
-
- return new ProjectDirectory(
- destinationPath,
- directoryPath,
- projectPath);
- }
- catch
- {
- CleanupDirectory(destinationPath);
- throw;
- }
-
- static void CopyDirectory(DirectoryInfo source, DirectoryInfo destination, bool recursive = true)
- {
- foreach (var file in source.EnumerateFiles())
- {
- file.CopyTo(Path.Combine(destination.FullName, file.Name));
- }
-
- if (!recursive)
- {
- return;
- }
-
- foreach (var directory in source.EnumerateDirectories())
- {
- if (directory.Name == "bin")
- {
- // Just in case someone has opened the project in an IDE or built it. We don't want to copy
- // these folders.
- continue;
- }
-
- var created = destination.CreateSubdirectory(directory.Name);
- if (directory.Name == "obj")
- {
- // Copy NuGet restore assets (viz all the files at the root of the obj directory, but stop there.)
- CopyDirectory(directory, created, recursive: false);
- }
- else
- {
- CopyDirectory(directory, created);
- }
- }
- }
-
- static void SetupDirectoryBuildFiles(string repoRoot, string testAppsRoot, string projectDestination)
- {
- var razorSdkDirectoryRoot = TestFacts.RazorSdkDirectoryRoot;
- var beforeDirectoryPropsContent =
-$@"<Project>
- <PropertyGroup>
- <RepoRoot>{repoRoot}</RepoRoot>
- <RazorSdkDirectoryRoot>{razorSdkDirectoryRoot}</RazorSdkDirectoryRoot>
- </PropertyGroup>
-</Project>";
- File.WriteAllText(Path.Combine(projectDestination, "Before.Directory.Build.props"), beforeDirectoryPropsContent);
-
- new List<string> { "Directory.Build.props", "Directory.Build.targets", }
- .ForEach(file =>
- {
- var source = Path.Combine(testAppsRoot, file);
- var destination = Path.Combine(projectDestination, file);
- File.Copy(source, destination);
- });
- }
-
- static void CopyRepositoryAssets(string projectRoot)
- {
- const string GlobalJsonFileName = "global.json";
- var globalJsonPath = Path.Combine(RepoRoot, GlobalJsonFileName);
-
- var destinationFile = Path.Combine(projectRoot, GlobalJsonFileName);
- File.Copy(globalJsonPath, destinationFile);
- }
- }
-
- protected ProjectDirectory(string solutionPath, string directoryPath, string projectFilePath)
- {
- SolutionPath = solutionPath;
- DirectoryPath = directoryPath;
- ProjectFilePath = projectFilePath;
- }
-
- public string DirectoryPath { get; }
-
- public string ProjectFilePath { get; }
-
- public string SolutionPath { get; }
-
- public string TargetFramework { get; set; } = "netstandard2.1";
-
- public string Configuration { get; set; } = TestProjectConfiguration;
-
- public string IntermediateOutputDirectory => Path.Combine("obj", Configuration, TargetFramework);
-
- public string BuildOutputDirectory => Path.Combine("bin", Configuration, TargetFramework);
-
- public string PublishOutputDirectory => Path.Combine(BuildOutputDirectory, "publish");
-
- internal void AddProjectFileContent(string content)
- {
- if (content == null)
- {
- throw new ArgumentNullException(nameof(content));
- }
-
- var existing = File.ReadAllText(ProjectFilePath);
- var updated = existing.Replace("<!-- Test Placeholder -->", content);
- File.WriteAllText(ProjectFilePath, updated);
- }
-
- internal void AddDirectoryBuildContent(string content)
- {
- if (content == null)
- {
- throw new ArgumentNullException(nameof(content));
- }
-
- var filepath = Path.Combine(DirectoryPath, "Directory.Build.props");
-
- var existing = File.ReadAllText(filepath);
- var updated = existing.Replace("<!-- Test Placeholder -->", content);
- File.WriteAllText(filepath, updated);
- }
-
- public void Dispose()
- {
- if (PreserveWorkingDirectory)
- {
- Console.WriteLine($"Skipping deletion of working directory {SolutionPath}");
- }
- else
- {
- CleanupDirectory(SolutionPath);
- }
- }
-
- internal static void CleanupDirectory(string filePath)
- {
- var tries = 5;
- var sleep = TimeSpan.FromSeconds(3);
-
- for (var i = 0; i < tries; i++)
- {
- try
- {
- Directory.Delete(filePath, recursive: true);
- return;
- }
- catch when (i < tries - 1)
- {
- Console.WriteLine($"Failed to delete directory {filePath}, trying again.");
- Thread.Sleep(sleep);
- }
- }
- }
-
- private static string GetTestAttribute(string key)
- {
- return typeof(ProjectDirectory).Assembly
- .GetCustomAttributes<AssemblyMetadataAttribute>()
- .FirstOrDefault(f => f.Key == key)
- ?.Value;
- }
-
- public override string ToString() => DirectoryPath;
- }
-}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/ProjectDirectoryTest.cs b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/ProjectDirectoryTest.cs
deleted file mode 100644
index 130a14ef8d..0000000000
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/ProjectDirectoryTest.cs
+++ /dev/null
@@ -1,21 +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 Xunit;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- public class ProjectDirectoryTest
- {
- [Fact]
- public void ProjectDirectory_IsNotSetToBePreserved()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
-
- // Act & Assert
- // This flag is only meant for local debugging and should not be set when checking in.
- Assert.False(project.PreserveWorkingDirectory);
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/PwaManifestTests.cs b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/PwaManifestTests.cs
deleted file mode 100644
index 464d361e70..0000000000
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/PwaManifestTests.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-using System.IO;
-using System.Linq;
-using System.Text.Json;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- public class PwaManifestTests
- {
- [Fact]
- public async Task Build_ServiceWorkerAssetsManifest_Works()
- {
- // Arrange
- var expectedExtensions = new[] { ".dll", ".pdb", ".js", ".wasm" };
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/p:ServiceWorkerAssetsManifest=service-worker-assets.js");
-
- Assert.BuildPassed(result);
-
- var buildOutputDirectory = project.BuildOutputDirectory;
-
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.webassembly.js");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", "dotnet.wasm");
- Assert.FileCountEquals(result, 1, Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "wasm"), "dotnet.*.js");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
-
- var staticWebAssets = Assert.FileExists(result, buildOutputDirectory, "standalone.StaticWebAssets.xml");
- Assert.FileContains(result, staticWebAssets, Path.Combine("netstandard2.1", "wwwroot"));
-
- var serviceWorkerAssetsManifest = Assert.FileExists(result, buildOutputDirectory, "wwwroot", "service-worker-assets.js");
- // Trim prefix 'self.assetsManifest = ' and suffix ';'
- var manifestContents = File.ReadAllText(serviceWorkerAssetsManifest).TrimEnd()[22..^1];
-
- var manifestContentsJson = JsonDocument.Parse(manifestContents);
- Assert.True(manifestContentsJson.RootElement.TryGetProperty("assets", out var assets));
- Assert.Equal(JsonValueKind.Array, assets.ValueKind);
-
- var entries = assets.EnumerateArray().Select(e => e.GetProperty("url").GetString()).OrderBy(e => e).ToArray();
- Assert.All(entries, e => expectedExtensions.Contains(Path.GetExtension(e)));
- }
-
- [Fact]
- public async Task Publish_UpdatesServiceWorkerVersionHash_WhenSourcesChange()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args: "/bl:initial.binlog /p:ServiceWorkerAssetsManifest=service-worker-assets.js");
-
- Assert.BuildPassed(result);
-
- var publishOutputDirectory = project.PublishOutputDirectory;
-
- var serviceWorkerFile = Assert.FileExists(result, publishOutputDirectory, "wwwroot", "serviceworkers", "my-service-worker.js");
- var version = File.ReadAllLines(serviceWorkerFile).Last();
- var match = Regex.Match(version, "\\/\\* Manifest version: (.{8}) \\*\\/");
- Assert.True(match.Success);
- Assert.Equal(2, match.Groups.Count);
- Assert.NotNull(match.Groups[1].Value);
- var capture = match.Groups[1].Value;
-
- // Act
- var cssFile = Path.Combine(project.DirectoryPath, "LinkToWebRoot", "css", "app.css");
- File.WriteAllText(cssFile, ".updated { }");
-
- // Assert
- var updatedResult = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args: "/bl:updated.binlog /p:ServiceWorkerAssetsManifest=service-worker-assets.js");
-
- Assert.BuildPassed(result);
-
- var updatedVersion = File.ReadAllLines(serviceWorkerFile).Last();
- var updatedMatch = Regex.Match(updatedVersion, "\\/\\* Manifest version: (.{8}) \\*\\/");
- Assert.True(updatedMatch.Success);
- Assert.Equal(2, updatedMatch.Groups.Count);
- Assert.NotNull(updatedMatch.Groups[1].Value);
- var updatedCapture = updatedMatch.Groups[1].Value;
-
- Assert.NotEqual(capture, updatedCapture);
- }
-
- [Fact]
- public async Task Publish_DeterministicAcrossBuilds_WhenNoSourcesChange()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args: "/bl:initial.binlog /p:ServiceWorkerAssetsManifest=service-worker-assets.js");
-
- Assert.BuildPassed(result);
-
- var publishOutputDirectory = project.PublishOutputDirectory;
-
- var serviceWorkerFile = Assert.FileExists(result, publishOutputDirectory, "wwwroot", "serviceworkers", "my-service-worker.js");
- var version = File.ReadAllLines(serviceWorkerFile).Last();
- var match = Regex.Match(version, "\\/\\* Manifest version: (.{8}) \\*\\/");
- Assert.True(match.Success);
- Assert.Equal(2, match.Groups.Count);
- Assert.NotNull(match.Groups[1].Value);
- var capture = match.Groups[1].Value;
-
- // Act && Assert
- var updatedResult = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args: "/bl:updated.binlog /p:ServiceWorkerAssetsManifest=service-worker-assets.js");
-
- Assert.BuildPassed(result);
-
- var updatedVersion = File.ReadAllLines(serviceWorkerFile).Last();
- var updatedMatch = Regex.Match(updatedVersion, "\\/\\* Manifest version: (.{8}) \\*\\/");
- Assert.True(updatedMatch.Success);
- Assert.Equal(2, updatedMatch.Groups.Count);
- Assert.NotNull(updatedMatch.Groups[1].Value);
- var updatedCapture = updatedMatch.Groups[1].Value;
-
- Assert.Equal(capture, updatedCapture);
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/TestFacts.cs b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/TestFacts.cs
deleted file mode 100644
index 1da03c94c6..0000000000
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/TestFacts.cs
+++ /dev/null
@@ -1,26 +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 System.Linq;
-using System.Reflection;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- public static class TestFacts
- {
- public static string DefaultNetCoreTargetFramework =>
- GetAttributeValue(nameof(DefaultNetCoreTargetFramework));
-
- public static string RazorSdkDirectoryRoot =>
- GetAttributeValue(nameof(RazorSdkDirectoryRoot));
-
- private static string GetAttributeValue(string name)
- {
- return Assembly
- .GetExecutingAssembly()
- .GetCustomAttributes<AssemblyMetadataAttribute>()
- .FirstOrDefault(a => a.Key == $"Testing.{name}")
- .Value;
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/WebAssemblyRuntimePackage.cs b/src/Components/WebAssembly/Build/test/BuildIntegrationTests/WebAssemblyRuntimePackage.cs
deleted file mode 100644
index d95ba1e41c..0000000000
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/WebAssemblyRuntimePackage.cs
+++ /dev/null
@@ -1,27 +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 System;
-using System.Linq;
-using System.Reflection;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- internal static class WebAssemblyRuntimePackage
- {
- public static readonly string ComponentsWebAssemblyRuntimePackageVersion;
- public static readonly string DotNetJsFileName;
-
- static WebAssemblyRuntimePackage()
- {
- ComponentsWebAssemblyRuntimePackageVersion = typeof(WebAssemblyRuntimePackage)
- .Assembly
- .GetCustomAttributes<AssemblyMetadataAttribute>()
- .FirstOrDefault(f => f.Key == "Testing.MicrosoftAspNetCoreComponentsWebAssemblyRuntimePackageVersion")
- ?.Value
- ?? throw new InvalidOperationException("Testing.MicrosoftAspNetCoreComponentsWebAssemblyRuntimePackageVersion was not found");
-
- DotNetJsFileName = $"dotnet.{ComponentsWebAssemblyRuntimePackageVersion}.js";
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/test/Microsoft.AspNetCore.Components.WebAssembly.Build.Tests.csproj b/src/Components/WebAssembly/Build/test/Microsoft.AspNetCore.Components.WebAssembly.Build.Tests.csproj
deleted file mode 100644
index e7b4c82883..0000000000
--- a/src/Components/WebAssembly/Build/test/Microsoft.AspNetCore.Components.WebAssembly.Build.Tests.csproj
+++ /dev/null
@@ -1,75 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
- <PropertyGroup>
- <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
-
- <!-- Exclude the TestFiles directory from default wildcards -->
- <DefaultItemExcludes>$(DefaultItemExcludes);TestFiles\**\*</DefaultItemExcludes>
- <BuildHelixPayload>false</BuildHelixPayload>
- </PropertyGroup>
-
- <ItemGroup>
- <!-- Embed test files so they can be referenced in tests -->
- <EmbeddedResource Include="TestFiles\**" />
- </ItemGroup>
-
- <PropertyGroup Condition="'$(GenerateBaselines)'=='true'">
- <DefineConstants>GENERATE_BASELINES;$(DefineConstants)</DefineConstants>
- </PropertyGroup>
-
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
- <DefineConstants>TRACE</DefineConstants>
- </PropertyGroup>
-
- <ItemGroup>
- <Reference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" />
- <Reference Include="Microsoft.AspNetCore.Components.WebAssembly.Runtime" />
- <Reference Include="Microsoft.Build.Framework" />
- <Reference Include="Microsoft.Build.Utilities.Core" />
- <!-- Avoid CS1705 errors due to mix of assemblies brought in transitively. -->
- <Reference Include="Microsoft.AspNetCore.Components" />
- </ItemGroup>
-
- <ItemGroup>
- <ProjectReference Include="..\..\testassets\StandaloneApp\StandaloneApp.csproj" />
- <Compile Include="$(SharedSourceRoot)CommandLineUtils\**\*.cs" />
- </ItemGroup>
-
- <ItemGroup>
- <AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
- <_Parameter1>Testing.RepoRoot</_Parameter1>
- <_Parameter2>$(RepoRoot)</_Parameter2>
- </AssemblyAttribute>
-
- <AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
- <_Parameter1>Testing.RazorSdkDirectoryRoot</_Parameter1>
- <_Parameter2>$(ArtifactsBinDir)Microsoft.NET.Sdk.Razor\$(Configuration)\sdk-output\</_Parameter2>
- </AssemblyAttribute>
-
- <AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
- <_Parameter1>Testing.MicrosoftAspNetCoreComponentsWebAssemblyRuntimePackageVersion</_Parameter1>
- <_Parameter2>$(MicrosoftAspNetCoreComponentsWebAssemblyRuntimePackageVersion)</_Parameter2>
- </AssemblyAttribute>
-
- <AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
- <_Parameter1>Testing.DefaultNetCoreTargetFramework</_Parameter1>
- <_Parameter2>$(DefaultNetCoreTargetFramework)</_Parameter2>
- </AssemblyAttribute>
- </ItemGroup>
-
- <Target Name="RestoreTestAssets" AfterTargets="Restore;Build" Condition="'$(DotNetBuildFromSource)' != 'true'">
- <ItemGroup>
- <_TestAsset Include="..\testassets\standalone\standalone.csproj" />
- <_TestAsset Include="..\testassets\blazorhosted\blazorhosted.csproj" />
- </ItemGroup>
-
- <MSBuild
- Projects="@(_TestAsset)"
- Targets="Restore"
- Properties="
- RepoRoot=$(RepoRoot);
- MicrosoftNetCompilersToolsetPackageVersion=$(MicrosoftNetCompilersToolsetPackageVersion);
- MicrosoftNETSdkRazorPackageVersion=$(MicrosoftNETSdkRazorPackageVersion)" />
- </Target>
-
-</Project>
diff --git a/src/Components/WebAssembly/Build/test/RuntimeDependenciesResolverTest.cs b/src/Components/WebAssembly/Build/test/RuntimeDependenciesResolverTest.cs
deleted file mode 100644
index 6fba8b34d9..0000000000
--- a/src/Components/WebAssembly/Build/test/RuntimeDependenciesResolverTest.cs
+++ /dev/null
@@ -1,181 +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 System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using Microsoft.AspNetCore.Testing;
-using Xunit;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
-{
- public class RuntimeDependenciesResolverTest
- {
- [Fact]
- [QuarantinedTest]
- public void FindsReferenceAssemblyGraph_ForStandaloneApp()
- {
- // Arrange
- var standaloneAppAssembly = typeof(StandaloneApp.Program).Assembly;
- var mainAssemblyLocation = standaloneAppAssembly.Location;
-
- var hintPaths = ReadContent(standaloneAppAssembly, "StandaloneApp.referenceHints.txt");
- var bclLocations = ReadContent(standaloneAppAssembly, "StandaloneApp.bclLocations.txt");
-
- var expectedContents = new[]
- {
- /*
- The current Mono WASM BCL forwards from netstandard.dll to various facade assemblies
- in which small bits of implementation live, such as System.Xml.XPath.XDocument. So
- if you reference netstandard, then you also reference System.Xml.XPath.XDocument.dll,
- even though you're very unlikely to be calling it at runtime. That's why the following
- list (for a very basic Blazor app) is longer than you'd expect.
-
- These redundant references could be stripped out during publishing, but it's still
- unfortunate that in development mode you'd see all these unexpected assemblies get
- fetched from the server. We should try to get the Mono WASM BCL reorganized so that
- all the implementation goes into mscorlib.dll, with the facade assemblies existing only
- in case someone (or some 3rd party assembly) references them directly, but with their
- implementations 100% forwarding to mscorlib.dll. Then in development you'd fetch far
- fewer assemblies from the server, and during publishing, illink would remove all the
- uncalled implementation code from mscorlib.dll anyway.
- */
- "Microsoft.AspNetCore.Components.dll",
- "Microsoft.AspNetCore.Components.Forms.dll",
- "Microsoft.AspNetCore.Components.Web.dll",
- "Microsoft.AspNetCore.Components.WebAssembly.dll",
- "Microsoft.Bcl.AsyncInterfaces.dll",
- "Microsoft.Extensions.Configuration.Abstractions.dll",
- "Microsoft.Extensions.Configuration.dll",
- "Microsoft.Extensions.Configuration.FileExtensions.dll",
- "Microsoft.Extensions.Configuration.Json.dll",
- "Microsoft.Extensions.DependencyInjection.Abstractions.dll",
- "Microsoft.Extensions.DependencyInjection.dll",
- "Microsoft.Extensions.FileProviders.Abstractions.dll",
- "Microsoft.Extensions.FileProviders.Physical.dll",
- "Microsoft.Extensions.FileSystemGlobbing.dll",
- "Microsoft.Extensions.Logging.dll",
- "Microsoft.Extensions.Logging.Abstractions.dll",
- "Microsoft.Extensions.Options.dll",
- "Microsoft.Extensions.Primitives.dll",
- "Microsoft.JSInterop.dll",
- "Microsoft.JSInterop.WebAssembly.dll",
- "Mono.Security.dll",
- "mscorlib.dll",
- "netstandard.dll",
- "StandaloneApp.dll",
- "System.dll",
- "System.Buffers.dll",
- "System.Collections.Concurrent.dll",
- "System.Collections.dll",
- "System.ComponentModel.Annotations.dll",
- "System.ComponentModel.DataAnnotations.dll",
- "System.ComponentModel.Composition.dll",
- "System.Core.dll",
- "System.Data.dll",
- "System.Data.DataSetExtensions.dll",
- "System.Diagnostics.Debug.dll",
- "System.Diagnostics.DiagnosticSource.dll",
- "System.Diagnostics.Tracing.dll",
- "System.Drawing.Common.dll",
- "System.IO.Compression.dll",
- "System.IO.Compression.FileSystem.dll",
- "System.Memory.dll",
- "System.Net.Http.dll",
- "System.Net.Http.Json.dll",
- "System.Net.Http.WebAssemblyHttpHandler.dll",
- "System.Numerics.dll",
- "System.Numerics.Vectors.dll",
- "System.Reflection.dll",
- "System.Resources.ResourceManager.dll",
- "System.Runtime.Extensions.dll",
- "System.Runtime.InteropServices.dll",
- "System.Runtime.CompilerServices.Unsafe.dll",
- "System.Runtime.Serialization.dll",
- "System.Runtime.dll",
- "System.ServiceModel.Internals.dll",
- "System.Text.Encodings.Web.dll",
- "System.Text.Json.dll",
- "System.Threading.dll",
- "System.Threading.Tasks.Extensions.dll",
- "System.Transactions.dll",
- "System.Xml.dll",
- "System.Xml.Linq.dll",
- "WebAssembly.Bindings.dll",
- "WebAssembly.Net.WebSockets.dll",
- }.OrderBy(i => i, StringComparer.Ordinal)
- .ToArray();
-
- // Act
-
- var paths = ResolveBlazorRuntimeDependencies
- .ResolveRuntimeDependenciesCore(
- mainAssemblyLocation,
- hintPaths,
- bclLocations);
-
- var contents = paths
- .Select(p => Path.GetFileName(p))
- .Where(p => Path.GetExtension(p) != ".pdb")
- .OrderBy(i => i, StringComparer.Ordinal)
- .ToArray();
-
- var expected = new HashSet<string>(expectedContents);
- var actual = new HashSet<string>(contents);
-
- var contentNotFound = expected.Except(actual);
- var additionalContentFound = actual.Except(expected);
-
- // Assert
- if (contentNotFound.Any() || additionalContentFound.Any())
- {
- throw new ContentMisMatchException
- {
- ContentNotFound = contentNotFound,
- AdditionalContentFound = additionalContentFound,
- };
- }
-
- Assert.Equal(expectedContents, contents);
- }
-
- private string[] ReadContent(Assembly standaloneAppAssembly, string fileName)
- {
- using var resource = standaloneAppAssembly.GetManifestResourceStream(fileName);
- using var streamReader = new StreamReader(resource);
-
- return streamReader.ReadToEnd().Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
- }
-
- private class ContentMisMatchException : Xunit.Sdk.XunitException
- {
- public IEnumerable<string> ContentNotFound { get; set; }
-
- public IEnumerable<string> AdditionalContentFound { get; set; }
-
- public override string Message
- {
- get
- {
- var error = new StringBuilder();
- if (ContentNotFound.Any())
- {
- error.Append($"Expected content not found: ")
- .AppendJoin(", ", ContentNotFound);
- }
-
- if (AdditionalContentFound.Any())
- {
- error.Append("Unexpected content found: ")
- .AppendJoin(", ", AdditionalContentFound);
- }
-
- return error.ToString();
- }
- }
- }
- }
-}
diff --git a/src/Components/WebAssembly/Build/testassets/Directory.Build.props b/src/Components/WebAssembly/Build/testassets/Directory.Build.props
deleted file mode 100644
index 109d34f261..0000000000
--- a/src/Components/WebAssembly/Build/testassets/Directory.Build.props
+++ /dev/null
@@ -1,30 +0,0 @@
-<Project>
- <Import Project="Before.Directory.Build.props" Condition="Exists('Before.Directory.Build.props')" />
-
- <!-- Test Placeholder -->
-
- <PropertyGroup>
- <RepoRoot Condition="'$(RepoRoot)' ==''">$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), global.json))\</RepoRoot>
- <ComponentsRoot>$(RepoRoot)src\Components\</ComponentsRoot>
- <BlazorBuildRoot>$(ComponentsRoot)WebAssembly\Build\src\</BlazorBuildRoot>
- <ReferenceBlazorBuildFromSourceProps>$(BlazorBuildRoot)ReferenceBlazorBuildFromSource.props</ReferenceBlazorBuildFromSourceProps>
-
- <!-- Workaround for https://github.com/dotnet/aspnetcore/issues/17308 -->
- <DefaultNetCoreTargetFramework>netcoreapp3.1</DefaultNetCoreTargetFramework>
-
- <EnableSourceLink>false</EnableSourceLink>
- <DeterministicSourcePaths>false</DeterministicSourcePaths>
- </PropertyGroup>
-
- <Import Project="$(RepoRoot)eng\Versions.props" />
-
- <ItemGroup>
- <!-- Use the sample compiler \ SDK that the rest of our build uses-->
- <PackageReference Include="Microsoft.Net.Compilers.Toolset"
- Version="$(MicrosoftNetCompilersToolsetPackageVersion)"
- PrivateAssets="all"
- IsImplicitlyDefined="true" />
- </ItemGroup>
-
- <Import Project="$(RepoRoot)src\Razor\Microsoft.NET.Sdk.Razor\src\build\netstandard2.0\Microsoft.NET.Sdk.Razor.props"/>
-</Project>
diff --git a/src/Components/WebAssembly/Build/testassets/Directory.Build.targets b/src/Components/WebAssembly/Build/testassets/Directory.Build.targets
deleted file mode 100644
index 8c119d5413..0000000000
--- a/src/Components/WebAssembly/Build/testassets/Directory.Build.targets
+++ /dev/null
@@ -1,2 +0,0 @@
-<Project>
-</Project>
diff --git a/src/Components/WebAssembly/Build/testassets/blazorhosted/blazorhosted.csproj b/src/Components/WebAssembly/Build/testassets/blazorhosted/blazorhosted.csproj
deleted file mode 100644
index bcdc9dba7d..0000000000
--- a/src/Components/WebAssembly/Build/testassets/blazorhosted/blazorhosted.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
-
- <PropertyGroup>
- <TargetFramework>net5.0</TargetFramework>
- </PropertyGroup>
-
- <ItemGroup>
- <ProjectReference Include="..\standalone\standalone.csproj" />
- </ItemGroup>
-
-</Project>
diff --git a/src/Components/WebAssembly/Build/testassets/standalone/standalone.csproj b/src/Components/WebAssembly/Build/testassets/standalone/standalone.csproj
deleted file mode 100644
index bbeafa77c2..0000000000
--- a/src/Components/WebAssembly/Build/testassets/standalone/standalone.csproj
+++ /dev/null
@@ -1,40 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
- <Import Project="$(ReferenceBlazorBuildFromSourceProps)" />
-
- <PropertyGroup>
- <TargetFramework>netstandard2.1</TargetFramework>
- <RazorLangVersion>3.0</RazorLangVersion>
- <ServiceWorkerAssetsManifest>custom-service-worker-assets.js</ServiceWorkerAssetsManifest>
- </PropertyGroup>
-
- <!-- Test Placeholder -->
-
- <ItemGroup>
- <PackageReference Include="Microsoft.AspNetCore.Components" Version="3.1.3" />
- <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Runtime" Version="$(MicrosoftAspNetCoreComponentsWebAssemblyRuntimePackageVersion)" />
- </ItemGroup>
-
- <ItemGroup>
- <ProjectReference Include="..\razorclasslibrary\RazorClassLibrary.csproj" />
- </ItemGroup>
-
- <ItemGroup>
- <!-- These assets should be treated as static web assets for publish purposes -->
- <Content Include="..\LinkBaseToWebRoot\**\*.js">
- <LinkBase>wwwroot\</LinkBase>
- </Content>
-
- <!-- This asset should be ignored as a static web assets as it defines CopyToPublishDirectory="false" -->
- <Content Update="wwwroot\css\app.css" CopyToPublishDirectory="false" />
-
- <!-- This asset should be treated as a static web asset and copied into the right location defined by its link attribute. -->
- <Content Include="LinkToWebRoot\css\app.css" Link="wwwroot\css\app.css" />
-
- <!-- This asset should not be treated as a static web asset as it is being linked out of the wwwroot folder. -->
- <Content Update="wwwroot\Fake-License.txt" Link="Excluded-Static-Web-Assets\Fake-License.txt" />
-
- <!-- The content from my-prod-service-worker.js should be published under the name my-service-worker.js -->
- <ServiceWorker Include="wwwroot\serviceworkers\my-service-worker.js" PublishedContent="wwwroot\serviceworkers\my-prod-service-worker.js" />
- </ItemGroup>
-
-</Project>
diff --git a/src/Components/WebAssembly/Compression/src/Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression.csproj b/src/Components/WebAssembly/Compression/src/Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression.csproj
deleted file mode 100644
index 7267b5ed54..0000000000
--- a/src/Components/WebAssembly/Compression/src/Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression.csproj
+++ /dev/null
@@ -1,10 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
- <PropertyGroup>
- <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
- <OutputType>Exe</OutputType>
- <AssemblyName>blazor-brotli</AssemblyName>
- <IsShippingPackage>false</IsShippingPackage>
- </PropertyGroup>
-
-</Project>
diff --git a/src/Components/WebAssembly/Compression/src/Program.cs b/src/Components/WebAssembly/Compression/src/Program.cs
deleted file mode 100644
index 804129166b..0000000000
--- a/src/Components/WebAssembly/Compression/src/Program.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using System;
-using System.IO;
-using System.IO.Compression;
-using System.Text.Json;
-using System.Threading.Tasks;
-
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build.BrotliCompression
-{
- class Program
- {
- private const int _error = -1;
-
- static async Task<int> Main(string[] args)
- {
- if (args.Length != 1)
- {
- Console.Error.WriteLine("Invalid argument count. Usage: 'blazor-brotli <<path-to-manifest>>'");
- return _error;
- }
-
- var manifestPath = args[0];
- if (!File.Exists(manifestPath))
- {
- Console.Error.WriteLine($"Manifest '{manifestPath}' does not exist.");
- return -1;
- }
-
- using var manifestStream = File.OpenRead(manifestPath);
-
- var manifest = await JsonSerializer.DeserializeAsync<ManifestData>(manifestStream);
- var result = 0;
- Parallel.ForEach(manifest.FilesToCompress, (file) =>
- {
- var inputPath = file.Source;
- var inputSource = file.InputSource;
- var targetCompressionPath = file.Target;
-
- if (!File.Exists(inputSource))
- {
- Console.WriteLine($"Skipping '{inputPath}' because '{inputSource}' does not exist.");
- return;
- }
-
- if (File.Exists(targetCompressionPath) && File.GetLastWriteTimeUtc(inputSource) < File.GetLastWriteTimeUtc(targetCompressionPath))
- {
- // Incrementalism. If input source doesn't exist or it exists and is not newer than the expected output, do nothing.
- Console.WriteLine($"Skipping '{inputPath}' because '{targetCompressionPath}' is newer than '{inputSource}'.");
- return;
- }
-
- try
- {
- Directory.CreateDirectory(Path.GetDirectoryName(targetCompressionPath));
-
- using var sourceStream = File.OpenRead(inputPath);
- using var fileStream = new FileStream(targetCompressionPath, FileMode.Create);
-
- var compressionLevel = CompressionLevel.Optimal;
- if (Environment.GetEnvironmentVariable("_BlazorWebAssemblyBuildTest_BrotliCompressionLevel_NoCompression") == "1")
- {
- compressionLevel = CompressionLevel.NoCompression;
- }
- using var stream = new BrotliStream(fileStream, compressionLevel);
-
- sourceStream.CopyTo(stream);
- }
- catch (Exception e)
- {
- Console.Error.WriteLine(e);
- result = -1;
- }
- });
-
- return result;
- }
-
- private class ManifestData
- {
- public CompressedFile[] FilesToCompress { get; set; }
- }
-
- private class CompressedFile
- {
- public string Source { get; set; }
-
- public string InputSource { get; set; }
-
- public string Target { get; set; }
- }
- }
-}
diff --git a/src/Components/WebAssembly/Compression/src/runtimeconfig.template.json b/src/Components/WebAssembly/Compression/src/runtimeconfig.template.json
deleted file mode 100644
index f022b7ffce..0000000000
--- a/src/Components/WebAssembly/Compression/src/runtimeconfig.template.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "rollForwardOnNoCandidateFx": 2
-} \ No newline at end of file
diff --git a/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj b/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
index 0447c61b7e..2aab0dbca7 100644
--- a/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
+++ b/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
@@ -15,6 +15,14 @@
<Reference Include="Microsoft.Extensions.Logging" />
<Reference Include="Microsoft.JSInterop.WebAssembly" />
+ <ProjectReference
+ Include="..\..\..\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj"
+ ReferenceOutputAssemblies="false"
+ SkipGetTargetFrameworkProperties="true"
+ UndefineProperties="TargetFramework"
+ Private="false"
+ Condition="'$(BuildNodeJS)' != 'false' and '$(BuildingInsideVisualStudio)' != 'true'" />
+
<!-- Tracking removing using https://github.com/dotnet/aspnetcore/issues/22283 -->
<ProjectReference
Include="..\..\WebAssemblyHttpHandler\src\Microsoft.AspNetCore.Components.WebAssembly.HttpHandler.csproj"
@@ -35,4 +43,13 @@
<InternalsVisibleTo Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication.Tests" />
<InternalsVisibleTo Include="BasicTestApp" />
</ItemGroup>
+
+ <PropertyGroup>
+ <BlazorWebAssemblyJSFile>..\..\..\Web.JS\dist\$(Configuration)\blazor.webassembly.js</BlazorWebAssemblyJSFile>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Content Include="$(BlazorWebAssemblyJSFile)" Pack="true" PackagePath="build\netstandard2.0\" LinkBase="build\netstandard2.0\" />
+ <Content Include="build\netstandard2.0\*.props" Pack="true" PackagePath="build\netstandard2.0\" />
+ </ItemGroup>
</Project>
diff --git a/src/Components/WebAssembly/WebAssembly/src/build/netstandard2.0/Microsoft.AspNetCore.Components.WebAssembly.props b/src/Components/WebAssembly/WebAssembly/src/build/netstandard2.0/Microsoft.AspNetCore.Components.WebAssembly.props
new file mode 100644
index 0000000000..41ae67bf35
--- /dev/null
+++ b/src/Components/WebAssembly/WebAssembly/src/build/netstandard2.0/Microsoft.AspNetCore.Components.WebAssembly.props
@@ -0,0 +1,5 @@
+<Project>
+ <PropertyGroup>
+ <BlazorWebAssemblyJSPath>$(MSBuildThisFileDirectory)blazor.webassembly.js</BlazorWebAssemblyJSPath>
+ </PropertyGroup>
+</Project>
diff --git a/src/Components/WebAssembly/testassets/HostedInAspNet.Client/HostedInAspNet.Client.csproj b/src/Components/WebAssembly/testassets/HostedInAspNet.Client/HostedInAspNet.Client.csproj
index 84dae61bf7..4994c3eb7d 100644
--- a/src/Components/WebAssembly/testassets/HostedInAspNet.Client/HostedInAspNet.Client.csproj
+++ b/src/Components/WebAssembly/testassets/HostedInAspNet.Client/HostedInAspNet.Client.csproj
@@ -1,12 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
- <TargetFramework>netstandard2.1</TargetFramework>
- <OutputType>Exe</OutputType>
- <ReferenceBlazorBuildLocally>true</ReferenceBlazorBuildLocally>
- <RazorLangVersion>3.0</RazorLangVersion>
- <!-- Disable compression in this project so that we can validate that it can be disabled -->
- <BlazorEnableCompression>false</BlazorEnableCompression>
+ <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
+ <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
+ <UseBlazorWebAssembly>true</UseBlazorWebAssembly>
+
<FixupWebAssemblyHttpHandlerReference>true</FixupWebAssemblyHttpHandlerReference>
</PropertyGroup>
diff --git a/src/Components/WebAssembly/testassets/MonoSanity/MonoSanity.csproj b/src/Components/WebAssembly/testassets/MonoSanity/MonoSanity.csproj
deleted file mode 100644
index 00b73a99ed..0000000000
--- a/src/Components/WebAssembly/testassets/MonoSanity/MonoSanity.csproj
+++ /dev/null
@@ -1,16 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
-
- <PropertyGroup>
- <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
- </PropertyGroup>
-
- <ItemGroup>
- <ProjectReference Include="..\MonoSanityClient\MonoSanityClient.csproj" />
- </ItemGroup>
-
- <ItemGroup>
- <Reference Include="Microsoft.AspNetCore" />
- <Reference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" />
- </ItemGroup>
-
-</Project>
diff --git a/src/Components/WebAssembly/testassets/MonoSanity/Program.cs b/src/Components/WebAssembly/testassets/MonoSanity/Program.cs
deleted file mode 100644
index 6481e4d4bc..0000000000
--- a/src/Components/WebAssembly/testassets/MonoSanity/Program.cs
+++ /dev/null
@@ -1,27 +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.Hosting;
-using Microsoft.Extensions.Hosting;
-
-namespace MonoSanity
-{
- public class Program
- {
- public static void Main(string[] args)
- {
- BuildWebHost(args).Run();
- }
-
- public static IHost BuildWebHost(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webHostBuilder =>
- {
- // We require this line because we run in Production environment
- // and static web assets are only on by default during development.
- webHostBuilder.UseStaticWebAssets();
- webHostBuilder.UseStartup<Startup>();
- })
- .Build();
- }
-}
diff --git a/src/Components/WebAssembly/testassets/MonoSanity/Startup.cs b/src/Components/WebAssembly/testassets/MonoSanity/Startup.cs
deleted file mode 100644
index 3cf349e787..0000000000
--- a/src/Components/WebAssembly/testassets/MonoSanity/Startup.cs
+++ /dev/null
@@ -1,28 +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.Builder;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace MonoSanity
-{
- public class Startup
- {
- public void ConfigureServices(IServiceCollection services)
- {
- }
-
- public void Configure(IApplicationBuilder app)
- {
- app.UseDeveloperExceptionPage();
- app.UseFileServer(new FileServerOptions() { EnableDefaultFiles = true, });
- app.UseBlazorFrameworkFiles();
- app.UseStaticFiles();
- app.UseRouting();
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapFallbackToFile("index.html");
- });
- }
- }
-}
diff --git a/src/Components/WebAssembly/testassets/MonoSanity/wwwroot/index.html b/src/Components/WebAssembly/testassets/MonoSanity/wwwroot/index.html
deleted file mode 100644
index 8a42e8e5d1..0000000000
--- a/src/Components/WebAssembly/testassets/MonoSanity/wwwroot/index.html
+++ /dev/null
@@ -1,158 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>Mono sanity check</title>
- <meta http-equiv="content-type" content="text/html; charset=utf-8" />
-</head>
-<body>
- <p>Simple sanity check to ensure the Mono runtime works in basic cases.</p>
-
- <fieldset>
- <legend>Add numbers</legend>
- <form id="addNumbers">
- <input id="addNumberA" value="123" /> +
- <input id="addNumberB" value="456" /> =
- <input id="addNumbersResult" readonly />
- <button type="submit" disabled>Go</button>
- </form>
- </fieldset>
-
- <fieldset>
- <legend>Repeat string</legend>
- <form id="repeatString">
- <input id="repeatStringStr" value="Hello" /> *
- <input id="repeatStringCount" value="3" type="number" /> =
- <input id="repeatStringResult" readonly />
- <button type="submit" disabled>Go</button>
- </form>
- </fieldset>
-
- <fieldset>
- <legend>Trigger .NET exception</legend>
- <form id="triggerException">
- <input id="triggerExceptionMessage" value="Your message here" />
- <button type="submit" disabled>Go</button>
- <div><textarea rows="5" cols="80" readonly id="triggerExceptionMessageStackTrace"></textarea></div>
- </form>
- </fieldset>
-
- <fieldset>
- <legend>Call JS from .NET</legend>
- <form id="callJs">
- <input id="callJsEvalExpression" value="location.href" />
- <button type="submit" disabled>Go</button>
- <div><textarea rows="5" cols="80" readonly id="callJsResult"></textarea></div>
- </form>
- </fieldset>
-
- <fieldset>
- <legend>Call JS from .NET (no boxing)</legend>
- <form id="callJsNoBoxing">
- <input id="callJsNoBoxingNumberA" value="28" /> /
- <input id="callJsNoBoxingNumberB" value="4" /> =
- <input id="callJsNoBoxingResult" readonly />
- <button type="submit" disabled>Go</button>
- </form>
- </fieldset>
-
- <fieldset>
- <legend>Get runtime OS</legend>
- <form id="getRuntimeInformation">
- <button type="submit" disabled>Get</button>
- <input id="getRuntimeInformationResult" readonly />
- </form>
- </fieldset>
-
- <p id="loadingIndicator">Loading...</p>
-
- <script src="loader.js"></script>
- <script>
- initMono(['MonoSanityClient.dll', 'MonoSanityClient.pdb'], function () {
- var buttons = document.getElementsByTagName('button');
- for (var i = 0; i < buttons.length; i++) {
- buttons[i].disabled = false;
- }
- el('loadingIndicator').style.display = 'none';
- window.isTestReady = true; // The Xunit code polls until this is true
- });
-
- el('addNumbers').onsubmit = function (evt) {
- evt.preventDefault();
- var a = parseInt(el('addNumberA').value);
- var b = parseInt(el('addNumberB').value);
- var result = invokeMonoMethod('MonoSanityClient', 'MonoSanityClient', 'Examples', 'AddNumbers', [a, b]);
- el('addNumbersResult').value = result;
- };
-
- el('repeatString').onsubmit = function (evt) {
- evt.preventDefault();
- var str = el('repeatStringStr').value;
- var count = parseInt(el('repeatStringCount').value);
- var result = invokeMonoMethod('MonoSanityClient', 'MonoSanityClient', 'Examples', 'RepeatString', [str, count]);
- el('repeatStringResult').value = result;
- };
-
- el('triggerException').onsubmit = function (evt) {
- evt.preventDefault();
- var message = el('triggerExceptionMessage').value;
- try {
- invokeMonoMethod('MonoSanityClient', 'MonoSanityClient', 'Examples', 'TriggerException', [message]);
- el('triggerExceptionMessageStackTrace').value = 'WARNING: No exception occurred';
- } catch (ex) {
- el('triggerExceptionMessageStackTrace').value = ex.toString();
- }
- };
-
- el('callJs').onsubmit = function (evt) {
- evt.preventDefault();
- var expression = el('callJsEvalExpression').value;
- var result = invokeMonoMethod('MonoSanityClient', 'MonoSanityClient', 'Examples', 'EvaluateJavaScript', [expression]);
- el('callJsResult').value = result;
- };
-
- el('callJsNoBoxing').onsubmit = function (evt) {
- evt.preventDefault();
- var a = parseInt(el('callJsNoBoxingNumberA').value);
- var b = parseInt(el('callJsNoBoxingNumberB').value);
- var result = invokeMonoMethod('MonoSanityClient', 'MonoSanityClient', 'Examples', 'CallJsNoBoxing', [a, b]);
- el('callJsNoBoxingResult').value = result;
- };
-
- el('getRuntimeInformation').onsubmit = function (evt) {
- evt.preventDefault();
- var result = invokeMonoMethod('MonoSanityClient', 'MonoSanityClient', 'Examples', 'GetRuntimeInformation', []);
- el('getRuntimeInformationResult').value = result;
- };
-
- function el(id) {
- return document.getElementById(id);
- }
-
- // Examples of functions we can invoke from .NET
-
- function getUserAgentString() {
- return navigator.userAgent;
- }
-
- function triggerJsException() {
- throw new Error('This is a JavaScript exception.');
- }
-
- function evaluateJsExpression(dotNetStringExpression) {
- var result = eval(dotnetStringToJavaScriptString(dotNetStringExpression));
- return result === null || result === undefined
- ? result // Pass through null/undefined so we can verify this is handled upstream
- : javaScriptStringToDotNetString(result.toString());
- }
-
- function divideNumbersUnmarshalled(a, b) {
- // In this example, neither the arguments nor return value are boxed
- // -- we expect to receive and return numbers directly
- if (b === 0) {
- throw new Error('Division by zero');
- }
- return a / b;
- }
- </script>
-</body>
-</html>
diff --git a/src/Components/WebAssembly/testassets/MonoSanity/wwwroot/loader.js b/src/Components/WebAssembly/testassets/MonoSanity/wwwroot/loader.js
deleted file mode 100644
index ad004cee37..0000000000
--- a/src/Components/WebAssembly/testassets/MonoSanity/wwwroot/loader.js
+++ /dev/null
@@ -1,128 +0,0 @@
-(function () {
- // Implement just enough of the DotNet.* API surface for unmarshalled interop calls to work
- // in the cases used in this project
- window.DotNet = {
- jsCallDispatcher: {
- findJSFunction: function (identifier) {
- return window[identifier];
- }
- }
- };
-
- window.initMono = function initMono(loadAssemblyUrls, onReadyCallback) {
- window.Module = {
- locateFile: function (fileName) {
- return fileName === 'dotnet.wasm' ? '/_framework/wasm/dotnet.wasm' : fileName;
- },
- onRuntimeInitialized: function () {
- var allAssemblyUrls = loadAssemblyUrls.concat([
- 'netstandard.dll',
- 'mscorlib.dll',
- 'System.dll',
- 'System.Core.dll',
- 'System.Net.Http.dll',
- 'System.Net.Http.WebAssemblyHttpHandler.dll',
- 'WebAssembly.Bindings.dll'
- ]);
-
- // For these tests we're using Mono's built-in mono_load_runtime_and_bcl util.
- // In real apps we don't use this because we want to have more fine-grained
- // control over how the requests are issued, what gets logged, etc., so for
- // real apps Blazor's Boot.WebAssembly.ts implements its own equivalent.
- MONO.mono_load_runtime_and_bcl(
- /* vfx_prefix */ 'myapp', // Virtual filesystem root - arbitrary value
- /* deploy_prefix */ '_framework/_bin',
- /* enable_debugging */ 1,
- allAssemblyUrls,
- onReadyCallback
- );
- }
- };
-
- addScriptTagsToDocument();
- };
-
- window.invokeMonoMethod = function invokeMonoMethod(assemblyName, namespace, typeName, methodName, args) {
- var assembly_load = Module.cwrap('mono_wasm_assembly_load', 'number', ['string']);
- var find_class = Module.cwrap('mono_wasm_assembly_find_class', 'number', ['number', 'string', 'string']);
- var find_method = Module.cwrap('mono_wasm_assembly_find_method', 'number', ['number', 'string', 'number']);
-
- var assembly = assembly_load(assemblyName);
- var type = find_class(assembly, namespace, typeName);
- var method = find_method(type, methodName, -1);
-
- var stack = Module.stackSave();
- try {
- var resultPtr = callMethod(method, null, args);
- return dotnetStringToJavaScriptString(resultPtr);
- }
- finally {
- Module.stackRestore(stack);
- }
- };
-
- window.dotnetStringToJavaScriptString = function dotnetStringToJavaScriptString(mono_obj) {
- if (mono_obj === 0)
- return null;
- var mono_string_get_utf8 = Module.cwrap('mono_wasm_string_get_utf8', 'number', ['number']);
- var raw = mono_string_get_utf8(mono_obj);
- var res = Module.UTF8ToString(raw);
- Module._free(raw);
- return res;
- };
-
- window.javaScriptStringToDotNetString = function dotnetStringToJavaScriptString(javaScriptString) {
- var mono_string = Module.cwrap('mono_wasm_string_from_js', 'number', ['string']);
- return mono_string(javaScriptString);
- };
-
- function callMethod(method, target, args) {
- var stack = Module.stackSave();
- var invoke_method = Module.cwrap('mono_wasm_invoke_method', 'number', ['number', 'number', 'number']);
-
- try {
- var argsBuffer = Module.stackAlloc(args.length);
- var exceptionFlagManagedInt = Module.stackAlloc(4);
- for (var i = 0; i < args.length; ++i) {
- var argVal = args[i];
- if (typeof argVal === 'number') {
- var managedInt = Module.stackAlloc(4);
- Module.setValue(managedInt, argVal, 'i32');
- Module.setValue(argsBuffer + i * 4, managedInt, 'i32');
- } else if (typeof argVal === 'string') {
- var managedString = javaScriptStringToDotNetString(argVal);
- Module.setValue(argsBuffer + i * 4, managedString, 'i32');
- } else {
- throw new Error('Unsupported arg type: ' + typeof argVal);
- }
- }
- Module.setValue(exceptionFlagManagedInt, 0, 'i32');
-
- var res = invoke_method(method, target, argsBuffer, exceptionFlagManagedInt);
-
- if (Module.getValue(exceptionFlagManagedInt, 'i32') !== 0) {
- throw new Error(dotnetStringToJavaScriptString(res));
- }
-
- return res;
- } finally {
- Module.stackRestore(stack);
- }
- }
-
- async function addScriptTagsToDocument() {
- var browserSupportsNativeWebAssembly = typeof WebAssembly !== 'undefined' && WebAssembly.validate;
- if (!browserSupportsNativeWebAssembly) {
- throw new Error('This browser does not support WebAssembly.');
- }
-
- var bootJson = await fetch('/_framework/blazor.boot.json').then(res => res.json());
- var dotNetJsResourceName = Object.keys(bootJson.resources.runtime)
- .filter(name => name.endsWith('.js'));
-
- var scriptElem = document.createElement('script');
- scriptElem.src = '/_framework/wasm/' + dotNetJsResourceName;
- document.body.appendChild(scriptElem);
- }
-
-})();
diff --git a/src/Components/WebAssembly/testassets/MonoSanityClient/Examples.cs b/src/Components/WebAssembly/testassets/MonoSanityClient/Examples.cs
deleted file mode 100644
index 7bae673449..0000000000
--- a/src/Components/WebAssembly/testassets/MonoSanityClient/Examples.cs
+++ /dev/null
@@ -1,63 +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 WebAssembly.JSInterop;
-using System;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Net.Http;
-
-namespace MonoSanityClient
-{
- public static class Examples
- {
- public static string AddNumbers(int a, int b)
- => (a + b).ToString();
-
- public static string RepeatString(string str, int count)
- {
- var result = new StringBuilder();
-
- for (var i = 0; i < count; i++)
- {
- result.Append(str);
- }
-
- return result.ToString();
- }
-
- public static void TriggerException(string message)
- {
- throw new InvalidOperationException(message);
- }
-
- public static string EvaluateJavaScript(string expression)
- {
- var result = InternalCalls.InvokeJSUnmarshalled<string, string, object, object>(out var exceptionMessage, "evaluateJsExpression", expression, null, null);
- if (exceptionMessage != null)
- {
- return $".NET got exception: {exceptionMessage}";
- }
-
- return $".NET received: {(result ?? "(NULL)")}";
- }
-
- public static string CallJsNoBoxing(int numberA, int numberB)
- {
- // For tests that call this method, we'll exercise the 'BlazorInvokeJS' code path
- // since that doesn't box the params
- var result = InternalCalls.InvokeJSUnmarshalled<int, int, object, int>(out var exceptionMessage, "divideNumbersUnmarshalled", numberA, numberB, null);
- if (exceptionMessage != null)
- {
- return $".NET got exception: {exceptionMessage}";
- }
-
- return $".NET received: {result}";
- }
-
- public static string GetRuntimeInformation()
- => $"OSDescription: '{RuntimeInformation.OSDescription}';"
- + $" OSArchitecture: '{RuntimeInformation.OSArchitecture}';"
- + $" IsOSPlatform(BROWSER): '{RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"))}'";
- }
-}
diff --git a/src/Components/WebAssembly/testassets/MonoSanityClient/InternalCalls.cs b/src/Components/WebAssembly/testassets/MonoSanityClient/InternalCalls.cs
deleted file mode 100644
index 0fb15337e8..0000000000
--- a/src/Components/WebAssembly/testassets/MonoSanityClient/InternalCalls.cs
+++ /dev/null
@@ -1,25 +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 System.Runtime.CompilerServices;
-
-namespace WebAssembly.JSInterop
-{
- // This file is copied from https://github.com/dotnet/jsinterop/blob/master/src/Mono.WebAssembly.Interop/InternalCalls.cs
- // so that MonoSanityClient can directly use the same underlying interop APIs (because
- // we're trying to observe the behavior of the Mono runtime itself, not JSInterop).
-
- internal class InternalCalls
- {
- // The exact namespace, type, and method names must match the corresponding entries
- // in driver.c in the Mono distribution
-
- // We're passing asyncHandle by ref not because we want it to be writable, but so it gets
- // passed as a pointer (4 bytes). We can pass 4-byte values, but not 8-byte ones.
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern string InvokeJSMarshalled(out string exception, ref long asyncHandle, string functionIdentifier, string argsJson);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern TRes InvokeJSUnmarshalled<T0, T1, T2, TRes>(out string exception, string functionIdentifier, T0 arg0, T1 arg1, T2 arg2);
- }
-}
diff --git a/src/Components/WebAssembly/testassets/MonoSanityClient/MonoSanityClient.csproj b/src/Components/WebAssembly/testassets/MonoSanityClient/MonoSanityClient.csproj
deleted file mode 100644
index 9df38c64eb..0000000000
--- a/src/Components/WebAssembly/testassets/MonoSanityClient/MonoSanityClient.csproj
+++ /dev/null
@@ -1,13 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk.Razor" TreatAsLocalProperty="BlazorWebAssemblyEnableLinking">
-
- <PropertyGroup>
- <TargetFramework>netstandard2.1</TargetFramework>
- <BlazorWebAssemblyEnableLinking>false</BlazorWebAssemblyEnableLinking>
- <OutputType>exe</OutputType>
- <RazorLangVersion>3.0</RazorLangVersion>
-
- <ReferenceBlazorBuildLocally>true</ReferenceBlazorBuildLocally>
- <!-- loader.js is hard-coded to assume it can load .pdbs regardless of Debug/Release configuration -->
- <BlazorEnableDebugging>true</BlazorEnableDebugging>
- </PropertyGroup>
-</Project>
diff --git a/src/Components/WebAssembly/testassets/MonoSanityClient/Program.cs b/src/Components/WebAssembly/testassets/MonoSanityClient/Program.cs
deleted file mode 100644
index 3bba6ffba6..0000000000
--- a/src/Components/WebAssembly/testassets/MonoSanityClient/Program.cs
+++ /dev/null
@@ -1,15 +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 MonoSanityClient
-{
- // Note: Not used at runtime. This exists only to give the server app some type to reference.
- // In realistic scenarios you'd have a Program class for real.
-
- public class Program
- {
- static void Main()
- {
- }
- }
-}
diff --git a/src/Components/WebAssembly/testassets/StandaloneApp/StandaloneApp.csproj b/src/Components/WebAssembly/testassets/StandaloneApp/StandaloneApp.csproj
index 8959978daa..9ebf31c365 100644
--- a/src/Components/WebAssembly/testassets/StandaloneApp/StandaloneApp.csproj
+++ b/src/Components/WebAssembly/testassets/StandaloneApp/StandaloneApp.csproj
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
- <TargetFramework>netstandard2.1</TargetFramework>
- <ReferenceBlazorBuildLocally>true</ReferenceBlazorBuildLocally>
- <RazorLangVersion>3.0</RazorLangVersion>
+ <TargetFramework>net5.0</TargetFramework>
+ <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
+ <UseBlazorWebAssembly>true</UseBlazorWebAssembly>
<FixupWebAssemblyHttpHandlerReference>true</FixupWebAssemblyHttpHandlerReference>
</PropertyGroup>
diff --git a/src/Components/WebAssembly/testassets/Wasm.Authentication.Client/Wasm.Authentication.Client.csproj b/src/Components/WebAssembly/testassets/Wasm.Authentication.Client/Wasm.Authentication.Client.csproj
index 6ade900b99..16fddd3ddc 100644
--- a/src/Components/WebAssembly/testassets/Wasm.Authentication.Client/Wasm.Authentication.Client.csproj
+++ b/src/Components/WebAssembly/testassets/Wasm.Authentication.Client/Wasm.Authentication.Client.csproj
@@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
- <TargetFramework>netstandard2.1</TargetFramework>
- <RazorLangVersion>3.0</RazorLangVersion>
- <ReferenceBlazorBuildLocally>true</ReferenceBlazorBuildLocally>
+ <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
+ <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
+ <UseBlazorWebAssembly>true</UseBlazorWebAssembly>
+
<FixupWebAssemblyHttpHandlerReference>true</FixupWebAssemblyHttpHandlerReference>
</PropertyGroup>
diff --git a/src/Components/benchmarkapps/Wasm.Performance/TestApp/Wasm.Performance.TestApp.csproj b/src/Components/benchmarkapps/Wasm.Performance/TestApp/Wasm.Performance.TestApp.csproj
index 57de501f63..54ec8b638d 100644
--- a/src/Components/benchmarkapps/Wasm.Performance/TestApp/Wasm.Performance.TestApp.csproj
+++ b/src/Components/benchmarkapps/Wasm.Performance/TestApp/Wasm.Performance.TestApp.csproj
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
- <TargetFramework>netstandard2.1</TargetFramework>
- <RazorLangVersion>3.0</RazorLangVersion>
- <ReferenceBlazorBuildLocally>true</ReferenceBlazorBuildLocally>
+ <TargetFramework>net5.0</TargetFramework>
+ <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
+ <UseBlazorWebAssembly>true</UseBlazorWebAssembly>
<IsTestAssetProject>true</IsTestAssetProject>
</PropertyGroup>
diff --git a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj
index fb063e00c8..256ea831e1 100644
--- a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj
+++ b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj
@@ -40,8 +40,6 @@
<ProjectReference Include="..\..\benchmarkapps\Wasm.Performance\TestApp\Wasm.Performance.TestApp.csproj" />
<ProjectReference Include="..\..\WebAssembly\testassets\HostedInAspNet.Client\HostedInAspNet.Client.csproj" />
<ProjectReference Include="..\..\WebAssembly\testassets\HostedInAspNet.Server\HostedInAspNet.Server.csproj" />
- <ProjectReference Include="..\..\WebAssembly\testassets\MonoSanityClient\MonoSanityClient.csproj" />
- <ProjectReference Include="..\..\WebAssembly\testassets\MonoSanity\MonoSanity.csproj" />
<ProjectReference Include="..\..\WebAssembly\testassets\StandaloneApp\StandaloneApp.csproj" />
<ProjectReference Include="..\..\WebAssembly\DevServer\src\Microsoft.AspNetCore.Components.WebAssembly.DevServer.csproj" />
<ProjectReference Include="..\testassets\BasicTestApp\BasicTestApp.csproj" />
diff --git a/src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs b/src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs
index f273f5e53f..1dd32e8221 100644
--- a/src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs
+++ b/src/Components/test/E2ETest/Tests/BootResourceCachingTest.cs
@@ -48,7 +48,6 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
var initialResourcesRequested = GetAndClearRequestedPaths();
Assert.NotEmpty(initialResourcesRequested.Where(path => path.EndsWith("/blazor.boot.json")));
Assert.NotEmpty(initialResourcesRequested.Where(path => path.EndsWith("/dotnet.wasm")));
- Assert.NotEmpty(initialResourcesRequested.Where(path => path.EndsWith("/dotnet.timezones.dat")));
Assert.NotEmpty(initialResourcesRequested.Where(path => path.EndsWith(".js")));
Assert.NotEmpty(initialResourcesRequested.Where(path => path.EndsWith(".dll")));
@@ -60,7 +59,6 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
var subsequentResourcesRequested = GetAndClearRequestedPaths();
Assert.NotEmpty(initialResourcesRequested.Where(path => path.EndsWith("/blazor.boot.json")));
Assert.Empty(subsequentResourcesRequested.Where(path => path.EndsWith("/dotnet.wasm")));
- Assert.Empty(subsequentResourcesRequested.Where(path => path.EndsWith("/dotnet.timezones.dat")));
Assert.NotEmpty(subsequentResourcesRequested.Where(path => path.EndsWith(".js")));
Assert.Empty(subsequentResourcesRequested.Where(path => path.EndsWith(".dll")));
}
diff --git a/src/Components/test/E2ETest/Tests/MonoSanityTest.cs b/src/Components/test/E2ETest/Tests/MonoSanityTest.cs
deleted file mode 100644
index 181a1f9974..0000000000
--- a/src/Components/test/E2ETest/Tests/MonoSanityTest.cs
+++ /dev/null
@@ -1,157 +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.E2ETest.Infrastructure;
-using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
-using Microsoft.AspNetCore.E2ETesting;
-using OpenQA.Selenium;
-using OpenQA.Selenium.Support.UI;
-using System;
-using System.Threading.Tasks;
-using Xunit;
-using Xunit.Abstractions;
-
-namespace Microsoft.AspNetCore.Components.E2ETest.Tests
-{
- public class MonoSanityTest : ServerTestBase<AspNetSiteServerFixture>
- {
- public MonoSanityTest(
- BrowserFixture browserFixture,
- AspNetSiteServerFixture serverFixture,
- ITestOutputHelper output)
- : base(browserFixture, serverFixture, output)
- {
- serverFixture.BuildWebHostMethod = MonoSanity.Program.BuildWebHost;
- }
-
- protected override void InitializeAsyncCore()
- {
- Navigate("/", noReload: true);
- WaitUntilMonoRunningInBrowser();
- }
-
- private void WaitUntilMonoRunningInBrowser()
- {
- new WebDriverWait(Browser, TimeSpan.FromSeconds(30)).Until(driver =>
- {
- return ((IJavaScriptExecutor)driver)
- .ExecuteScript("return window.isTestReady;");
- });
- }
-
- [Fact]
- public void HasTitle()
- {
- Assert.Equal("Mono sanity check", Browser.Title);
- }
-
- [Fact]
- public void CanAddNumbers()
- {
- SetValue(Browser, "addNumberA", "1001");
- SetValue(Browser, "addNumberB", "2002");
- Browser.FindElement(By.CssSelector("#addNumbers button")).Click();
-
- Assert.Equal("3003", GetValue(Browser, "addNumbersResult"));
- }
-
- [Fact]
- public void CanRepeatString()
- {
- SetValue(Browser, "repeatStringStr", "Test");
- SetValue(Browser, "repeatStringCount", "5");
- Browser.FindElement(By.CssSelector("#repeatString button")).Click();
-
- Assert.Equal("TestTestTestTestTest", GetValue(Browser, "repeatStringResult"));
- }
-
- [Fact]
- public void CanReceiveDotNetExceptionInJavaScript()
- {
- SetValue(Browser, "triggerExceptionMessage", "Hello from test");
- Browser.FindElement(By.CssSelector("#triggerException button")).Click();
-
- Assert.Contains("Hello from test", GetValue(Browser, "triggerExceptionMessageStackTrace"));
- }
-
- [Fact]
- public void CanCallJavaScriptFromDotNet()
- {
- SetValue(Browser, "callJsEvalExpression", "getUserAgentString()");
- Browser.FindElement(By.CssSelector("#callJs button")).Click();
- var result = GetValue(Browser, "callJsResult");
- Assert.StartsWith(".NET received: Mozilla", result);
- }
-
- [Fact]
- public void CanReceiveJavaScriptExceptionInDotNet()
- {
- SetValue(Browser, "callJsEvalExpression", "triggerJsException()");
- Browser.FindElement(By.CssSelector("#callJs button")).Click();
- var result = GetValue(Browser, "callJsResult");
- Assert.StartsWith(".NET got exception: This is a JavaScript exception.", result);
-
- // Also verify we got a stack trace
- Assert.Contains("at triggerJsException", result);
- }
-
- [Fact]
- public void CanEvaluateJsExpressionThatResultsInNull()
- {
- SetValue(Browser, "callJsEvalExpression", "null");
- Browser.FindElement(By.CssSelector("#callJs button")).Click();
- var result = GetValue(Browser, "callJsResult");
- Assert.Equal(".NET received: (NULL)", result);
- }
-
- [Fact]
- public void CanEvaluateJsExpressionThatResultsInUndefined()
- {
- SetValue(Browser, "callJsEvalExpression", "console.log('Not returning anything')");
- Browser.FindElement(By.CssSelector("#callJs button")).Click();
- var result = GetValue(Browser, "callJsResult");
- Assert.Equal(".NET received: (NULL)", result);
- }
-
- [Fact]
- public void CanCallJsFunctionsWithoutBoxing()
- {
- SetValue(Browser, "callJsNoBoxingNumberA", "108");
- SetValue(Browser, "callJsNoBoxingNumberB", "4");
- Browser.FindElement(By.CssSelector("#callJsNoBoxing button")).Click();
- Assert.Equal(".NET received: 27", GetValue(Browser, "callJsNoBoxingResult"));
- }
-
- [Fact]
- public void CanCallJsFunctionsWithoutBoxingAndReceiveException()
- {
- SetValue(Browser, "callJsNoBoxingNumberA", "1");
- SetValue(Browser, "callJsNoBoxingNumberB", "0");
- Browser.FindElement(By.CssSelector("#callJsNoBoxing button")).Click();
-
- Assert.StartsWith(".NET got exception: Division by zero", GetValue(Browser, "callJsNoBoxingResult"));
- }
-
- [Fact]
- public void ReturnsExpectedRuntimeInformation()
- {
- Browser.FindElement(By.CssSelector("#getRuntimeInformation button")).Click();
- Assert.Equal(
- "OSDescription: 'web'; OSArchitecture: 'X86'; IsOSPlatform(BROWSER): 'True'",
- GetValue(Browser, "getRuntimeInformationResult"));
- }
-
- private static string GetValue(IWebDriver webDriver, string elementId)
- {
- var element = webDriver.FindElement(By.Id(elementId));
- return element.GetAttribute("value");
- }
-
- private static void SetValue(IWebDriver webDriver, string elementId, string value)
- {
- var element = webDriver.FindElement(By.Id(elementId));
- element.Clear();
- element.SendKeys(value);
- }
- }
-}
diff --git a/src/Components/test/E2ETest/Tests/WebAssemblyAuthenticationTests.cs b/src/Components/test/E2ETest/Tests/WebAssemblyAuthenticationTests.cs
index 8fce8f9513..998144b33c 100644
--- a/src/Components/test/E2ETest/Tests/WebAssemblyAuthenticationTests.cs
+++ b/src/Components/test/E2ETest/Tests/WebAssemblyAuthenticationTests.cs
@@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
[Fact]
public void WasmAuthentication_Loads()
{
- Assert.Equal("Wasm.Authentication.Client", Browser.Title);
+ Browser.Equal("Wasm.Authentication.Client", () => Browser.Title);
}
[Fact]
@@ -408,8 +408,8 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
private void WaitUntilLoaded(bool skipHeader = false)
{
- new WebDriverWait(Browser, TimeSpan.FromSeconds(30)).Until(
- driver => driver.FindElement(By.TagName("app")).Text != "Loading...");
+ Browser.Exists(By.TagName("app"));
+ Browser.True(() => Browser.FindElement(By.TagName("app")).Text != "Loading...");
if (!skipHeader)
{
diff --git a/src/Components/test/E2ETest/Tests/WebAssemblyGlobalizationTest.cs b/src/Components/test/E2ETest/Tests/WebAssemblyGlobalizationTest.cs
index bf5fcb6f62..a18343dd75 100644
--- a/src/Components/test/E2ETest/Tests/WebAssemblyGlobalizationTest.cs
+++ b/src/Components/test/E2ETest/Tests/WebAssemblyGlobalizationTest.cs
@@ -10,11 +10,13 @@ using OpenQA.Selenium;
using Xunit;
using Xunit.Abstractions;
-namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
+namespace Microsoft.AspNetCore.Components.E2ETest.Tests
{
// For now this is limited to server-side execution because we don't have the ability to set the
// culture in client-side Blazor.
- public class WebAssemblyGlobalizationTest : GlobalizationTest<ToggleExecutionModeServerFixture<Program>>
+ // This type is internal since localization currently does not work.
+ // Make it public onc https://github.com/dotnet/runtime/issues/38124 is resolved.
+ internal class WebAssemblyGlobalizationTest : GlobalizationTest<ToggleExecutionModeServerFixture<Program>>
{
public WebAssemblyGlobalizationTest(
BrowserFixture browserFixture,
diff --git a/src/Components/test/E2ETest/Tests/WebAssemblyLocalizationTest.cs b/src/Components/test/E2ETest/Tests/WebAssemblyLocalizationTest.cs
index 81c99ccf67..184c62e33c 100644
--- a/src/Components/test/E2ETest/Tests/WebAssemblyLocalizationTest.cs
+++ b/src/Components/test/E2ETest/Tests/WebAssemblyLocalizationTest.cs
@@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
{
}
- [Theory]
+ [Theory(Skip = "https://github.com/dotnet/runtime/issues/38124")]
[InlineData("en-US", "Hello!")]
[InlineData("fr-FR", "Bonjour!")]
public void CanSetCultureAndReadLocalizedResources(string culture, string message)
diff --git a/src/Components/test/E2ETest/Tests/WebAssemblyLoggingTest.cs b/src/Components/test/E2ETest/Tests/WebAssemblyLoggingTest.cs
index 5d83568f50..c6440eecd8 100644
--- a/src/Components/test/E2ETest/Tests/WebAssemblyLoggingTest.cs
+++ b/src/Components/test/E2ETest/Tests/WebAssemblyLoggingTest.cs
@@ -52,7 +52,8 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
AssertLogContainsCriticalMessages(
"crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]",
"[Custom logger] Unhandled exception rendering component: Here is the outer exception",
- "System.InvalidTimeZoneException: Here is the outer exception ---> System.ArithmeticException: Here is the inner exception",
+ "System.InvalidTimeZoneException: Here is the outer exception",
+ "System.ArithmeticException: Here is the inner exception",
"at BasicTestApp.ErrorComponent.ThrowInner");
}
diff --git a/src/Components/test/E2ETest/Tests/WebAssemblyStringComparisonTest.cs b/src/Components/test/E2ETest/Tests/WebAssemblyStringComparisonTest.cs
index 9a38268403..61eb71c618 100644
--- a/src/Components/test/E2ETest/Tests/WebAssemblyStringComparisonTest.cs
+++ b/src/Components/test/E2ETest/Tests/WebAssemblyStringComparisonTest.cs
@@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
{
}
- [Fact]
+ [Fact(Skip = "https://github.com/dotnet/runtime/issues/38126")]
public void InvariantCultureWorksAsExpected()
{
Navigate(ServerPathBase, noReload: false);
diff --git a/src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj b/src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj
index 1cba39fcde..3923c0d5c0 100644
--- a/src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj
+++ b/src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
- <TargetFramework>netstandard2.1</TargetFramework>
- <RazorLangVersion>3.0</RazorLangVersion>
+ <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
+ <UseBlazorWebAssembly>true</UseBlazorWebAssembly>
+ <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
- <ReferenceBlazorBuildLocally>true</ReferenceBlazorBuildLocally>
<!-- Must be defined before ReferenceFromSource.props is imported -->
<AdditionalRunArguments>--pathbase /subdir</AdditionalRunArguments>
diff --git a/src/Components/test/testassets/BasicTestApp/Program.cs b/src/Components/test/testassets/BasicTestApp/Program.cs
index 01d7c29f00..b512810bc1 100644
--- a/src/Components/test/testassets/BasicTestApp/Program.cs
+++ b/src/Components/test/testassets/BasicTestApp/Program.cs
@@ -42,7 +42,7 @@ namespace BasicTestApp
builder.Logging.Services.AddSingleton<ILoggerProvider, PrependMessageLoggerProvider>(s =>
new PrependMessageLoggerProvider(builder.Configuration["Logging:PrependMessage:Message"], s.GetService<IJSRuntime>()));
-
+
var host = builder.Build();
ConfigureCulture(host);
diff --git a/src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js b/src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js
index a1f7975a90..dbbba1e0c8 100644
--- a/src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js
+++ b/src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js
@@ -258,4 +258,4 @@ function receiveDotNetObjectByRefAsync(incomingData) {
testDto: testDto
};
});
-}
+} \ No newline at end of file
diff --git a/src/Components/test/testassets/ComponentsApp.App/ComponentsApp.App.csproj b/src/Components/test/testassets/ComponentsApp.App/ComponentsApp.App.csproj
index 470c119f13..2680ed8709 100644
--- a/src/Components/test/testassets/ComponentsApp.App/ComponentsApp.App.csproj
+++ b/src/Components/test/testassets/ComponentsApp.App/ComponentsApp.App.csproj
@@ -1,8 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
- <TargetFramework>netstandard2.0</TargetFramework>
- <RazorLangVersion>3.0</RazorLangVersion>
+ <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
</PropertyGroup>
<ItemGroup>
diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj
index f5ae6e70b0..d9d6b2dda8 100644
--- a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj
+++ b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj
@@ -71,10 +71,6 @@
<_Parameter2>$(TargetFramework)</_Parameter2>
<_Parameter3></_Parameter3>
</AssemblyAttribute>
- <AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
- <_Parameter1>Test.RazorSdkDirectoryRoot</_Parameter1>
- <_Parameter2>$(RazorSdkDirectoryRoot)</_Parameter2>
- </AssemblyAttribute>
</ItemGroup>
<Target Name="PrepareForTest" BeforeTargets="GetAssemblyAttributes" Condition="$(DesignTimeBuild) != true">
diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs
index 9050f00b15..ffa5da4de1 100644
--- a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs
+++ b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorWasmTemplateTest.cs
@@ -44,7 +44,7 @@ namespace Templates.Test
public async Task BlazorWasmStandaloneTemplate_Works()
{
var project = await ProjectFactory.GetOrCreateProject("blazorstandalone", Output);
- project.TargetFramework = "netstandard2.1";
+ project.RuntimeIdentifier = "browser-wasm";
var createResult = await project.RunDotNetNewAsync("blazorwasm");
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
@@ -135,7 +135,7 @@ namespace Templates.Test
public async Task BlazorWasmStandalonePwaTemplate_Works()
{
var project = await ProjectFactory.GetOrCreateProject("blazorstandalonepwa", Output);
- project.TargetFramework = "netstandard2.1";
+ project.RuntimeIdentifier = "browser-wasm";
var createResult = await project.RunDotNetNewAsync("blazorwasm", args: new[] { "--pwa" });
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", project, createResult));
@@ -457,8 +457,6 @@ namespace Templates.Test
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", project, aspNetProcess.Process));
await aspNetProcess.AssertStatusCode("/", HttpStatusCode.OK, "text/html");
- // We only do brotli precompression for published apps
- await AssertCompressionFormat(aspNetProcess, "gzip");
if (BrowserFixture.IsHostAutomationSupported())
{
aspNetProcess.VisitInBrowser(Browser);
@@ -597,7 +595,6 @@ namespace Templates.Test
File.WriteAllText(Path.Combine(serverProject.TemplatePublishDir, "appsettings.json"), testAppSettings);
}
-
private (ProcessEx, string url) RunPublishedStandaloneBlazorProject(Project project)
{
var publishDir = Path.Combine(project.TemplatePublishDir, "wwwroot");
diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/Infrastructure/TemplateTests.props.in b/src/ProjectTemplates/BlazorTemplates.Tests/Infrastructure/TemplateTests.props.in
index 0b1eeedf1b..1ffcbf83d1 100644
--- a/src/ProjectTemplates/BlazorTemplates.Tests/Infrastructure/TemplateTests.props.in
+++ b/src/ProjectTemplates/BlazorTemplates.Tests/Infrastructure/TemplateTests.props.in
@@ -34,5 +34,8 @@
several versions older than latest. To avoid a cyclical dependency, this package reference is added to override the bundled version.
Since this is a project reference, we must explicitly import the props file and also specify the output location of the SDK directory.
-->
+ <PropertyGroup>
+ <RazorSdkDirectoryRoot>${ArtifactsBinDir}Microsoft.NET.Sdk.Razor\${Configuration}\sdk-output\</RazorSdkDirectoryRoot>
+ </PropertyGroup>
<Import Project="${RepoRoot}src\Razor\Microsoft.NET.Sdk.Razor\src\build\netstandard2.0\Microsoft.NET.Sdk.Razor.props" Condition="'$(UsingMicrosoftNETSdkWeb)' == 'true' OR '$(RazorSdkCurrentVersionProps)' != ''" />
</Project>
diff --git a/src/ProjectTemplates/Shared/Project.cs b/src/ProjectTemplates/Shared/Project.cs
index 505716e01e..939a49089f 100644
--- a/src/ProjectTemplates/Shared/Project.cs
+++ b/src/ProjectTemplates/Shared/Project.cs
@@ -39,10 +39,10 @@ namespace Templates.Test.Helpers
public string ProjectGuid { get; set; }
public string TemplateOutputDir { get; set; }
public string TargetFramework { get; set; } = GetAssemblyMetadata("Test.DefaultTargetFramework");
- public string RazorSdkDirectoryRoot { get; set; } = GetAssemblyMetadata("Test.RazorSdkDirectoryRoot");
+ public string RuntimeIdentifier { get; set; } = string.Empty;
- public string TemplateBuildDir => Path.Combine(TemplateOutputDir, "bin", "Debug", TargetFramework);
- public string TemplatePublishDir => Path.Combine(TemplateOutputDir, "bin", "Release", TargetFramework, "publish");
+ public string TemplateBuildDir => Path.Combine(TemplateOutputDir, "bin", "Debug", TargetFramework, RuntimeIdentifier);
+ public string TemplatePublishDir => Path.Combine(TemplateOutputDir, "bin", "Release", TargetFramework, RuntimeIdentifier, "publish");
public ITestOutputHelper Output { get; set; }
public IMessageSink DiagnosticsMessageSink { get; set; }
@@ -117,9 +117,7 @@ namespace Templates.Test.Helpers
// Avoid restoring as part of build or publish. These projects should have already restored as part of running dotnet new. Explicitly disabling restore
// should avoid any global contention and we can execute a build or publish in a lock-free way
- var razorSDKarg = string.IsNullOrEmpty(RazorSdkDirectoryRoot) ? string.Empty : $"/p:RazorSdkDirectoryRoot={RazorSdkDirectoryRoot}";
-
- using var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish --no-restore -c Release /bl {razorSDKarg} {additionalArgs}", packageOptions);
+ using var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish --no-restore -c Release /bl {additionalArgs}", packageOptions);
await result.Exited;
CaptureBinLogOnFailure(result);
return new ProcessResult(result);
@@ -132,9 +130,7 @@ namespace Templates.Test.Helpers
// Avoid restoring as part of build or publish. These projects should have already restored as part of running dotnet new. Explicitly disabling restore
// should avoid any global contention and we can execute a build or publish in a lock-free way
- var razorSDKarg = string.IsNullOrEmpty(RazorSdkDirectoryRoot) ? string.Empty : $"/p:RazorSdkDirectoryRoot={RazorSdkDirectoryRoot}";
-
- using var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"build --no-restore -c Debug /bl {razorSDKarg} {additionalArgs}", packageOptions);
+ using var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"build --no-restore -c Debug /bl {additionalArgs}", packageOptions);
await result.Exited;
CaptureBinLogOnFailure(result);
return new ProcessResult(result);
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/ComponentsWebAssembly-CSharp.Client.csproj.in b/src/ProjectTemplates/Web.ProjectTemplates/ComponentsWebAssembly-CSharp.Client.csproj.in
index 4b856535b2..24c38f6480 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/ComponentsWebAssembly-CSharp.Client.csproj.in
+++ b/src/ProjectTemplates/Web.ProjectTemplates/ComponentsWebAssembly-CSharp.Client.csproj.in
@@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
- <TargetFramework>netstandard2.1</TargetFramework>
- <RazorLangVersion>3.0</RazorLangVersion>
+ <TargetFramework>${DefaultNetCoreTargetFramework}</TargetFramework>
+ <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
+ <UseBlazorWebAssembly>true</UseBlazorWebAssembly>
<!--#if PWA -->
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
<!--#endif -->
@@ -13,7 +14,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="${MicrosoftAspNetCoreComponentsWebAssemblyPackageVersion}" />
- <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="${MicrosoftAspNetCoreComponentsWebAssemblyBuildPackageVersion}" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="${MicrosoftAspNetCoreComponentsWebAssemblyDevServerPackageVersion}" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="${MicrosoftAspNetCoreComponentsWebAssemblyAuthenticationPackageVersion}" Condition="'$(IndividualLocalAuth)' == 'true'" />
<PackageReference Include="Microsoft.Authentication.WebAssembly.Msal" Version="${MicrosoftAuthenticationWebAssemblyMsalPackageVersion}" Condition="'$(OrganizationalAuth)' == 'true' OR '$(IndividualB2CAuth)' == 'true'" />
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/ComponentsWebAssembly-CSharp.Shared.csproj.in b/src/ProjectTemplates/Web.ProjectTemplates/ComponentsWebAssembly-CSharp.Shared.csproj.in
index d4c395e8cb..797f21c216 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/ComponentsWebAssembly-CSharp.Shared.csproj.in
+++ b/src/ProjectTemplates/Web.ProjectTemplates/ComponentsWebAssembly-CSharp.Shared.csproj.in
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <TargetFramework>netstandard2.1</TargetFramework>
+ <TargetFramework>${DefaultNetCoreTargetFramework}</TargetFramework>
</PropertyGroup>
</Project>
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj b/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj
index d36a8d5050..e142e3233a 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj
+++ b/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj
@@ -35,7 +35,6 @@
<PackageVersionVariableReference Include="$(RepoRoot)src\Middleware\Diagnostics.EntityFrameworkCore\src\Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.csproj" />
<PackageVersionVariableReference Include="$(RepoRoot)src\Mvc\Mvc.Razor.RuntimeCompilation\src\Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.csproj" />
<PackageVersionVariableReference Include="$(ComponentsWebAssemblyProjectsRoot)WebAssembly\src\Microsoft.AspNetCore.Components.WebAssembly.csproj" />
- <PackageVersionVariableReference Include="$(ComponentsWebAssemblyProjectsRoot)Build\src\Microsoft.AspNetCore.Components.WebAssembly.Build.csproj" />
<PackageVersionVariableReference Include="$(ComponentsWebAssemblyProjectsRoot)DevServer\src\Microsoft.AspNetCore.Components.WebAssembly.DevServer.csproj" />
<PackageVersionVariableReference Include="$(ComponentsWebAssemblyProjectsRoot)Server\src\Microsoft.AspNetCore.Components.WebAssembly.Server.csproj" />
<PackageVersionVariableReference Include="$(ComponentsWebAssemblyProjectsRoot)WebAssembly.Authentication\src\Microsoft.AspNetCore.Components.WebAssembly.Authentication.csproj" />
diff --git a/src/ProjectTemplates/test/Infrastructure/TemplateTests.props.in b/src/ProjectTemplates/test/Infrastructure/TemplateTests.props.in
index 227bffd7a5..c3e1a9634d 100644
--- a/src/ProjectTemplates/test/Infrastructure/TemplateTests.props.in
+++ b/src/ProjectTemplates/test/Infrastructure/TemplateTests.props.in
@@ -34,5 +34,8 @@
We reference the project to ensure it's built before the other projects that use it. Since this is a project reference, we
must explicitly import the props file and also specify the output location of the SDK directory.
-->
+ <PropertyGroup>
+ <RazorSdkDirectoryRoot>${ArtifactsBinDir}Microsoft.NET.Sdk.Razor\${Configuration}\sdk-output\</RazorSdkDirectoryRoot>
+ </PropertyGroup>
<Import Project="${RepoRoot}src\Razor\Microsoft.NET.Sdk.Razor\src\build\netstandard2.0\Microsoft.NET.Sdk.Razor.props" Condition="'$(UsingMicrosoftNETSdkWeb)' == 'true' OR '$(RazorSdkCurrentVersionProps)' != ''" />
</Project>
diff --git a/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj b/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj
index 5bc7af6a32..69e08a8c83 100644
--- a/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj
+++ b/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<!-- Shared testing infrastructure for running E2E tests using selenium -->
<Import Project="$(SharedSourceRoot)E2ETesting\E2ETesting.props" />
@@ -65,10 +65,6 @@
<_Parameter1>Test.DefaultTargetFramework</_Parameter1>
<_Parameter2>$(DefaultNetCoreTargetFramework)</_Parameter2>
</AssemblyAttribute>
- <AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
- <_Parameter1>Test.RazorSdkDirectoryRoot</_Parameter1>
- <_Parameter2>$(RazorSdkDirectoryRoot)</_Parameter2>
- </AssemblyAttribute>
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute" Condition="'$(ContinuousIntegrationBuild)' == 'true'">
<_Parameter1>ContinuousIntegrationBuild</_Parameter1>
<_Parameter2>true</_Parameter2>
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Application.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Application.cs
index 9c63203f66..73a05d570f 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Application.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Application.cs
@@ -39,6 +39,7 @@ namespace Microsoft.AspNetCore.Razor.Tools
Commands.Add(new ShutdownCommand(this));
Commands.Add(new DiscoverCommand(this));
Commands.Add(new GenerateCommand(this));
+ Commands.Add(new BrotliCompressCommand(this));
}
public CancellationToken CancellationToken { get; }
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/BrotliCompressCommand.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/BrotliCompressCommand.cs
new file mode 100644
index 0000000000..ca758cd6d3
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/BrotliCompressCommand.cs
@@ -0,0 +1,70 @@
+// 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.IO;
+using System.IO.Compression;
+using System.Threading.Tasks;
+using Microsoft.Extensions.CommandLineUtils;
+
+namespace Microsoft.AspNetCore.Razor.Tools
+{
+ internal class BrotliCompressCommand : CommandBase
+ {
+ public BrotliCompressCommand(Application parent)
+ : base(parent, "brotli")
+ {
+ Sources = Option("-s", "files to compress", CommandOptionType.MultipleValue);
+ Outputs = Option("-o", "Output file path", CommandOptionType.MultipleValue);
+ CompressionLevelOption = Option("-c", "Compression level", CommandOptionType.SingleValue);
+ }
+
+ public CommandOption Sources { get; }
+
+ public CommandOption Outputs { get; }
+
+ public CommandOption CompressionLevelOption { get; }
+
+ public CompressionLevel CompressionLevel { get; private set; } = CompressionLevel.Optimal;
+
+ protected override bool ValidateArguments()
+ {
+ if (Sources.Values.Count != Outputs.Values.Count)
+ {
+ Error.WriteLine($"{Sources.Description} has {Sources.Values.Count}, but {Outputs.Description} has {Outputs.Values.Count} values.");
+ return false;
+ }
+
+ if (CompressionLevelOption.HasValue())
+ {
+ if (!Enum.TryParse<CompressionLevel>(CompressionLevelOption.Value(), out var value))
+ {
+ Error.WriteLine($"Invalid option {CompressionLevelOption.Value()} for {CompressionLevelOption.Template}.");
+ return false;
+ }
+
+ CompressionLevel = value;
+ }
+
+ return true;
+ }
+
+ protected override Task<int> ExecuteCoreAsync()
+ {
+ Parallel.For(0, Sources.Values.Count, i =>
+ {
+ var source = Sources.Values[i];
+ var output = Outputs.Values[i];
+
+ using var sourceStream = File.OpenRead(source);
+ using var fileStream = new FileStream(output, FileMode.Create);
+
+ using var stream = new BrotliStream(fileStream, CompressionLevel);
+
+ sourceStream.CopyTo(stream);
+ });
+
+ return Task.FromResult(ExitCodeSuccess);
+ }
+ }
+}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Assert.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Assert.cs
index 72e8d79e49..8648ede045 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Assert.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Assert.cs
@@ -9,6 +9,7 @@ using System.IO.Compression;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
+using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
@@ -238,6 +239,26 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
}
}
+ public static void FileHashEquals(MSBuildResult result, string filePath, string expectedSha256Base64)
+ {
+ if (result == null)
+ {
+ throw new ArgumentNullException(nameof(result));
+ }
+
+ filePath = Path.Combine(result.Project.DirectoryPath, filePath);
+ FileExists(result, filePath);
+
+ var actual = File.ReadAllBytes(filePath);
+ using var algorithm = SHA256.Create();
+ var actualSha256 = algorithm.ComputeHash(actual);
+ var actualSha256Base64 = Convert.ToBase64String(actualSha256);
+ if (expectedSha256Base64 != actualSha256Base64)
+ {
+ throw new MSBuildXunitException(result, $"File hashes for {filePath} do not match. Expected {expectedSha256Base64}, Actual {actualSha256Base64}");
+ }
+ }
+
public static void FileContainsLine(MSBuildResult result, string filePath, string match)
{
if (result == null)
@@ -298,7 +319,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
return filePath;
}
- public static void FileCountEquals(MSBuildResult result, int expected, string directoryPath, string searchPattern)
+ public static void FileCountEquals(MSBuildResult result, int expected, string directoryPath, string searchPattern, SearchOption searchOption = SearchOption.AllDirectories)
{
if (result == null)
{
@@ -319,7 +340,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
if (Directory.Exists(directoryPath))
{
- var files = Directory.GetFiles(directoryPath, searchPattern, SearchOption.AllDirectories);
+ var files = Directory.GetFiles(directoryPath, searchPattern, searchOption);
if (files.Length != expected)
{
throw new FileCountException(result, expected, directoryPath, searchPattern, files);
@@ -508,6 +529,44 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
}
}
+ public static void AssemblyContainsResource(MSBuildResult result, string assemblyPath, string resourceName)
+ {
+ if (result == null)
+ {
+ throw new ArgumentNullException(nameof(result));
+ }
+
+ assemblyPath = Path.Combine(result.Project.DirectoryPath, Path.Combine(assemblyPath));
+
+ var resources = GetAssemblyResourceNames(assemblyPath);
+ Assert.Contains(resourceName, resources);
+ }
+
+ public static void AssemblyDoesNotContainResource(MSBuildResult result, string assemblyPath, string resourceName)
+ {
+ if (result == null)
+ {
+ throw new ArgumentNullException(nameof(result));
+ }
+
+ assemblyPath = Path.Combine(result.Project.DirectoryPath, Path.Combine(assemblyPath));
+
+ var resources = GetAssemblyResourceNames(assemblyPath);
+ Assert.DoesNotContain(resourceName, resources);
+ }
+
+ private static IEnumerable<string> GetAssemblyResourceNames(string assemblyPath)
+ {
+ using var file = File.OpenRead(assemblyPath);
+ using var peReader = new PEReader(file);
+ var metadataReader = peReader.GetMetadataReader();
+ return metadataReader.ManifestResources.Where(r => !r.IsNil).Select(r =>
+ {
+ var resource = metadataReader.GetManifestResource(r);
+ return metadataReader.GetString(resource.Name);
+ }).ToArray();
+ }
+
public static void AssemblyHasAttribute(MSBuildResult result, string assemblyPath, string fullTypeName)
{
if (result == null)
@@ -538,14 +597,20 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
}
}
- private abstract class MSBuildXunitException : Xunit.Sdk.XunitException
+ public class MSBuildXunitException : Xunit.Sdk.XunitException
{
protected MSBuildXunitException(MSBuildResult result)
{
Result = result;
}
- protected abstract string Heading { get; }
+ public MSBuildXunitException(MSBuildResult result, string heading)
+ {
+ Result = result;
+ Heading = heading;
+ }
+
+ protected virtual string Heading { get; }
public MSBuildResult Result { get; }
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildIntegrationTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildIntegrationTest.cs
index 5a64947f8b..4d1b03af59 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildIntegrationTest.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildIntegrationTest.cs
@@ -119,7 +119,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
[InitializeTestProject("SimpleMvc")]
public async Task Build_RazorOutputPath_SetToNonDefault()
{
- var customOutputPath = Path.Combine("bin", Configuration, TargetFramework, "Razor");
+ var customOutputPath = Path.Combine("bin", Configuration, Project.TargetFramework, "Razor");
var result = await DotnetMSBuild("Build", $"/p:RazorOutputPath={customOutputPath}");
Assert.BuildPassed(result);
@@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
[InitializeTestProject("SimpleMvc")]
public async Task Build_MvcRazorOutputPath_SetToNonDefault()
{
- var customOutputPath = Path.Combine("bin", Configuration, TargetFramework, "Razor");
+ var customOutputPath = Path.Combine("bin", Configuration, Project.TargetFramework, "Razor");
var result = await DotnetMSBuild("Build", $"/p:MvcRazorOutputPath={customOutputPath}");
Assert.BuildPassed(result);
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildServerIntegrationTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildServerIntegrationTest.cs
index 1fe81b585a..23faba7d40 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildServerIntegrationTest.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildServerIntegrationTest.cs
@@ -12,12 +12,10 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
{
public class BuildServerIntegrationTest : MSBuildIntegrationTestBase, IClassFixture<BuildServerTestFixture>
{
- private BuildServerTestFixture _buildServer;
public BuildServerIntegrationTest(BuildServerTestFixture buildServer)
: base(buildServer)
{
- _buildServer = buildServer;
}
[Fact]
@@ -171,7 +169,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
var toolAssembly = Path.Combine(publishDir, "rzc.dll");
var result = await DotnetMSBuild(
"Build",
- $"/p:_RazorForceBuildServer=true /p:_RazorToolAssembly={toolAssembly}",
+ $"/p:_RazorForceBuildServer=true /p:_RazorSdkToolAssembly={toolAssembly}",
suppressBuildServer: true); // We don't want to specify a pipe name
Assert.BuildPassed(result);
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildVariables.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildVariables.cs
index 544e98e281..797d244625 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildVariables.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildVariables.cs
@@ -20,5 +20,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
public static string RazorSdkDirectoryRoot => TestAssemblyMetadata.SingleOrDefault(a => a.Key == "RazorSdkDirectoryRoot").Value;
public static string RepoRoot => TestAssemblyMetadata.SingleOrDefault(a => a.Key == "Testing.RepoRoot").Value;
+
+ public static string DefaultNetCoreTargetFramework => TestAssemblyMetadata.SingleOrDefault(a => a.Key == "DefaultNetCoreTargetFramework").Value;
}
}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildWithComponents31IntegrationTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildWithComponents31IntegrationTest.cs
index a3422fe9ea..6c09b10104 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildWithComponents31IntegrationTest.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildWithComponents31IntegrationTest.cs
@@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
[InitializeTestProject("blazor31")]
public async Task Build_Components_WithDotNetCoreMSBuild_Works()
{
- TargetFramework = "netcoreapp3.1";
+ Project.TargetFramework = "netcoreapp3.1";
var result = await DotnetMSBuild("Build");
Assert.BuildPassed(result);
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildWithComponentsIntegrationTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildWithComponentsIntegrationTest.cs
index ce867b6b8d..fa6e78c7d7 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildWithComponentsIntegrationTest.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildWithComponentsIntegrationTest.cs
@@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
[InitializeTestProject("ComponentLibrary")]
public async Task Build_WithoutRazorLangVersion_ProducesWarning()
{
- TargetFramework = "netstandard2.0";
+ Project.TargetFramework = "netstandard2.0";
var result = await DotnetMSBuild("Build", "/p:RazorLangVersion=");
Assert.BuildPassed(result, allowWarnings: true);
@@ -80,7 +80,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
[InitializeTestProject("ComponentLibrary")]
public async Task Building_NetstandardComponentLibrary()
{
- TargetFramework = "netstandard2.0";
+ Project.TargetFramework = "netstandard2.0";
// Build
var result = await DotnetMSBuild("Build");
@@ -96,7 +96,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
[InitializeTestProject("ComponentLibrary")]
public async Task Build_DoesNotProduceRefsDirectory()
{
- TargetFramework = "netstandard2.0";
+ Project.TargetFramework = "netstandard2.0";
// Build
var result = await DotnetMSBuild("Build");
@@ -111,7 +111,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
[InitializeTestProject("ComponentLibrary")]
public async Task Publish_DoesNotProduceRefsDirectory()
{
- TargetFramework = "netstandard2.0";
+ Project.TargetFramework = "netstandard2.0";
// Build
var result = await DotnetMSBuild("Publish");
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/DesignTimeBuildIntegrationTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/DesignTimeBuildIntegrationTest.cs
index f5baa8b4b9..8576598145 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/DesignTimeBuildIntegrationTest.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/DesignTimeBuildIntegrationTest.cs
@@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
[InitializeTestProject("ComponentLibrary")]
public async Task RazorGenerateComponentDesignTime_ReturnsRazorComponentWithTargetPath()
{
- TargetFramework = "netstandard2.0";
+ Project.TargetFramework = "netstandard2.0";
var result = await DotnetMSBuild("RazorGenerateComponentDesignTime;_IntrospectRazorComponentWithTargetPath");
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/FIleThumbPrint.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/FIleThumbPrint.cs
index 0266ecdd1b..81faa7d2a1 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/FIleThumbPrint.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/FIleThumbPrint.cs
@@ -2,7 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Security.Cryptography;
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
@@ -36,6 +38,24 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
return new FileThumbPrint(path, lastWriteTimeUtc, hash);
}
+ /// <summary>
+ /// Returns a list of thumbprints for all files (recursive) in the specified directory, sorted by file paths.
+ /// </summary>
+ internal static List<FileThumbPrint> CreateFolderThumbprint(ProjectDirectory project, string directoryPath, params string[] filesToIgnore)
+ {
+ directoryPath = System.IO.Path.Combine(project.DirectoryPath, directoryPath);
+ var files = Directory.GetFiles(directoryPath).Where(p => !filesToIgnore.Contains(p));
+ var thumbprintLookup = new List<FileThumbPrint>();
+ foreach (var file in files)
+ {
+ var thumbprint = Create(file);
+ thumbprintLookup.Add(thumbprint);
+ }
+
+ thumbprintLookup.Sort(Comparer<FileThumbPrint>.Create((a, b) => StringComparer.Ordinal.Compare(a.Path, b.Path)));
+ return thumbprintLookup;
+ }
+
public bool Equals(FileThumbPrint other)
{
return
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/InitializeTestProjectAttribute.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/InitializeTestProjectAttribute.cs
index ccc1b06af9..8293d4488a 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/InitializeTestProjectAttribute.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/InitializeTestProjectAttribute.cs
@@ -36,12 +36,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
throw new InvalidOperationException($"This should be used on a class derived from {typeof(MSBuildIntegrationTestBase)}");
}
- MSBuildIntegrationTestBase.Project = ProjectDirectory.Create(_originalProjectName, _testProjectName, _baseDirectory, _additionalProjects, _language);
-#if NETCOREAPP
- MSBuildIntegrationTestBase.TargetFramework = "net5.0";
-#else
-#error Target frameworks need to be updated
-#endif
+ MSBuildIntegrationTestBase.Project = ProjectDirectory.Create(_originalProjectName, new ProjectDirectory.ProjectDirectoryOptions(_baseDirectory, _testProjectName, _language), _additionalProjects);
}
public override void After(MethodInfo methodUnderTest)
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MSBuildIntegrationTestBase.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MSBuildIntegrationTestBase.cs
index ff17163390..cc9fd1009a 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MSBuildIntegrationTestBase.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MSBuildIntegrationTestBase.cs
@@ -16,7 +16,6 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
public abstract class MSBuildIntegrationTestBase
{
private static readonly AsyncLocal<ProjectDirectory> _project = new AsyncLocal<ProjectDirectory>();
- private static readonly AsyncLocal<string> _projectTfm = new AsyncLocal<string>();
protected MSBuildIntegrationTestBase(BuildServerTestFixtureBase buildServer)
{
@@ -31,9 +30,9 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
#error Configuration not supported
#endif
- protected string IntermediateOutputPath => Path.Combine("obj", Configuration, TargetFramework);
+ protected string IntermediateOutputPath => Path.Combine("obj", Configuration, Project.TargetFramework);
- protected string OutputPath => Path.Combine("bin", Configuration, TargetFramework);
+ protected string OutputPath => Path.Combine("bin", Configuration, Project.TargetFramework);
protected string PublishOutputPath => Path.Combine(OutputPath, "publish");
@@ -50,12 +49,6 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
protected string RazorComponentIntermediateOutputPath => Path.Combine(IntermediateOutputPath, "RazorDeclaration");
- internal static string TargetFramework
- {
- get => _projectTfm.Value;
- set => _projectTfm.Value = value;
- }
-
protected BuildServerTestFixtureBase BuildServer { get; set; }
internal Task<MSBuildResult> DotnetMSBuild(
@@ -111,16 +104,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
}
internal void AddProjectFileContent(string content)
- {
- if (content == null)
- {
- throw new ArgumentNullException(nameof(content));
- }
-
- var existing = File.ReadAllText(Project.ProjectFilePath);
- var updated = existing.Replace("<!-- Test Placeholder -->", content);
- File.WriteAllText(Project.ProjectFilePath, updated);
- }
+ => Project.AddProjectFileContent(content);
internal void ReplaceContent(string content, params string[] paths)
{
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MSBuildProcessManager.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MSBuildProcessManager.cs
index e9a9216782..5ab553d6bb 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MSBuildProcessManager.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MSBuildProcessManager.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
@@ -15,6 +16,47 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
{
internal static class MSBuildProcessManager
{
+ internal static Task<MSBuildResult> DotnetMSBuild(
+ ProjectDirectory project,
+ string target = "Build",
+ string args = null,
+ string buildServerPipeName = null)
+ {
+ var buildArgumentList = new List<string>
+ {
+ // Disable node-reuse. We don't want msbuild processes to stick around
+ // once the test is completed.
+ "/nr:false",
+
+ // Always generate a bin log for debugging purposes
+ "/bl",
+
+ // Let the test app know it is running as part of a test.
+ "/p:RunningAsTest=true",
+
+ $"/p:MicrosoftNETCoreAppRuntimeVersion={BuildVariables.MicrosoftNETCoreAppRuntimeVersion}",
+ $"/p:MicrosoftNetCompilersToolsetPackageVersion={BuildVariables.MicrosoftNetCompilersToolsetPackageVersion}",
+ $"/p:RazorSdkDirectoryRoot={BuildVariables.RazorSdkDirectoryRoot}",
+ $"/p:RepoRoot={BuildVariables.RepoRoot}",
+ $"/p:Configuration={project.Configuration}",
+ $"/t:{target}",
+ args,
+ };
+
+ if (buildServerPipeName != null)
+ {
+ buildArgumentList.Add($@"/p:_RazorBuildServerPipeName=""{buildServerPipeName}""");
+ }
+
+ var buildArguments = string.Join(" ", buildArgumentList);
+
+ return RunProcessAsync(
+ project,
+ buildArguments,
+ timeout: null,
+ MSBuildProcessKind.Dotnet);
+ }
+
public static async Task<MSBuildResult> RunProcessAsync(
ProjectDirectory project,
string arguments,
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Microsoft.NET.Sdk.Razor.IntegrationTests.csproj b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Microsoft.NET.Sdk.Razor.IntegrationTests.csproj
index a28e8d3e91..a1e160322e 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Microsoft.NET.Sdk.Razor.IntegrationTests.csproj
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Microsoft.NET.Sdk.Razor.IntegrationTests.csproj
@@ -51,6 +51,11 @@
</AssemblyAttribute>
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
+ <_Parameter1>DefaultNetCoreTargetFramework</_Parameter1>
+ <_Parameter2>$(DefaultNetCoreTargetFramework)</_Parameter2>
+ </AssemblyAttribute>
+
+ <AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
<_Parameter1>MicrosoftNetCompilersToolsetPackageVersion</_Parameter1>
<_Parameter2>$(MicrosoftNetCompilersToolsetPackageVersion)</_Parameter2>
</AssemblyAttribute>
@@ -72,6 +77,11 @@
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\src\BootJsonData.cs" LinkBase="Wasm" />
+ <Compile Include="..\src\AssetsManifestFile.cs" LinkBase="Wasm" />
+ </ItemGroup>
+
<Target Name="GenerateTestData" BeforeTargets="GetAssemblyAttributes">
<Exec Condition="'$(OS)' == 'Windows_NT'" Command="&quot;$(NuGetPackageRoot)vswhere\$(VSWhereVersion)\tools\vswhere.exe&quot; -latest -prerelease -property installationPath -requires Microsoft.Component.MSBuild" ConsoleToMsBuild="true" StandardErrorImportance="high">
<Output TaskParameter="ConsoleOutput" PropertyName="_VSInstallDir" />
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MvcBuildIntegrationTestLegacy.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MvcBuildIntegrationTestLegacy.cs
index dbc85428aa..f73bdeb2d6 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MvcBuildIntegrationTestLegacy.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MvcBuildIntegrationTestLegacy.cs
@@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
IClassFixture<LegacyBuildServerTestFixture>
{
public abstract string TestProjectName { get; }
- public abstract new string TargetFramework { get; }
+ public abstract string TargetFramework { get; }
public virtual string OutputFileName => $"{TestProjectName}.dll";
public MvcBuildIntegrationTestLegacy(LegacyBuildServerTestFixture buildServer)
@@ -24,8 +24,8 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
protected IDisposable CreateTestProject()
{
- Project = ProjectDirectory.Create(TestProjectName, TestProjectName, string.Empty, Array.Empty<string>(), "C#");
- MSBuildIntegrationTestBase.TargetFramework = TargetFramework;
+ Project = ProjectDirectory.Create(TestProjectName);
+ Project.TargetFramework = TargetFramework;
return new Disposable();
}
@@ -52,7 +52,6 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
result,
Path.Combine(IntermediateOutputPath, $"{TestProjectName}.TagHelpers.output.cache"),
@"""Name"":""SimpleMvc.SimpleTagHelper""");
-
}
}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/PackIntegrationTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/PackIntegrationTest.cs
index dfe9c90f48..6b0688031c 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/PackIntegrationTest.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/PackIntegrationTest.cs
@@ -258,7 +258,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
[InitializeTestProject("ComponentLibrary")]
public async Task Pack_DoesNotIncludeAnyCustomPropsFiles_WhenNoStaticAssetsAreAvailable()
{
- MSBuildIntegrationTestBase.TargetFramework = "netstandard2.0";
+ Project.TargetFramework = "netstandard2.0";
var result = await DotnetMSBuild("Pack");
@@ -282,7 +282,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
[InitializeTestProject("PackageLibraryTransitiveDependency")]
public async Task Pack_Incremental_DoesNotRegenerateCacheAndPropsFiles()
{
- TargetFramework = "netstandard2.0";
+ Project.TargetFramework = "netstandard2.0";
var result = await DotnetMSBuild("Pack");
Assert.BuildPassed(result, allowWarnings: true);
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/ProjectDirectory.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/ProjectDirectory.cs
index e2a28a1b06..d0d0e571f4 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/ProjectDirectory.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/ProjectDirectory.cs
@@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
-using Microsoft.AspNetCore.Testing;
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
{
@@ -18,9 +17,28 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
public bool PreserveWorkingDirectory { get; set; }
#endif
- public static ProjectDirectory Create(string originalProjectName, string targetProjectName, string baseDirectory, string[] additionalProjects, string language)
+ public readonly struct ProjectDirectoryOptions
{
- var destinationPath = Path.Combine(Path.GetTempPath(), "Razor", baseDirectory, Path.GetRandomFileName());
+ public ProjectDirectoryOptions(string baseDirectory, string targetProjectName, string language)
+ {
+ BaseDirectory = baseDirectory;
+ TargetProjectName = targetProjectName;
+ Language = language;
+ }
+
+ public string TargetProjectName { get; }
+
+ public string BaseDirectory { get; }
+
+ public string Language { get; }
+ }
+
+ public static ProjectDirectory Create(string projectName, params string[] additionalProjects) => Create(projectName, default, additionalProjects);
+
+ public static ProjectDirectory Create(string originalProjectName, ProjectDirectoryOptions options, params string[] additionalProjects)
+ {
+ // string targetProjectName, string baseDirectory,
+ var destinationPath = Path.Combine(Path.GetTempPath(), "Razor", options.BaseDirectory ?? string.Empty, Path.GetRandomFileName());
Directory.CreateDirectory(destinationPath);
try
@@ -50,30 +68,27 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
}
// Rename the csproj/fsproj
- string extension;
- if (language.Equals("C#", StringComparison.OrdinalIgnoreCase))
- {
- extension = ".csproj";
- }
- else if (language.Equals("F#", StringComparison.OrdinalIgnoreCase))
+ var extension = ".csproj";
+ if (string.Equals("F#", options.Language, StringComparison.OrdinalIgnoreCase))
{
extension = ".fsproj";
}
- else
+
+ var directoryPath = Path.Combine(destinationPath, originalProjectName);
+ var projectFilePath = Path.Combine(directoryPath, originalProjectName + extension);
+ if (options.TargetProjectName != null)
{
- throw new InvalidOperationException($"Language {language} is not supported.");
+ var newProjectFilePath = Path.Combine(directoryPath, options.TargetProjectName + extension);
+ File.Move(projectFilePath, newProjectFilePath);
+ projectFilePath = newProjectFilePath;
}
- var directoryPath = Path.Combine(destinationPath, originalProjectName);
- var oldProjectFilePath = Path.Combine(directoryPath, originalProjectName + extension);
- var newProjectFilePath = Path.Combine(directoryPath, targetProjectName + extension);
- File.Move(oldProjectFilePath, newProjectFilePath);
CopyRepositoryAssets(repositoryRoot, destinationPath);
return new ProjectDirectory(
destinationPath,
directoryPath,
- newProjectFilePath);
+ projectFilePath);
}
catch
{
@@ -127,7 +142,7 @@ $@"<Project>
</Project>";
File.WriteAllText(Path.Combine(projectDestination, "Before.Directory.Build.props"), beforeDirectoryPropsContent);
- new List<string> { "Directory.Build.props", "Directory.Build.targets", "RazorTest.Introspection.targets" }
+ new List<string> { "Directory.Build.props", "Directory.Build.targets", "RazorTest.Introspection.targets", "blazor.webassembly.js" }
.ForEach(file =>
{
var source = Path.Combine(testAppsRoot, file);
@@ -149,6 +164,12 @@ $@"<Project>
}
}
+ public ProjectDirectory GetSibling(string projectName)
+ {
+ var siblingDirectory = Path.GetFullPath(Path.Combine(DirectoryPath, "..", projectName));
+ return new ProjectDirectory(SolutionPath, siblingDirectory, Path.Combine(siblingDirectory, projectName + ".csproj"));
+ }
+
protected ProjectDirectory(string solutionPath, string directoryPath, string projectFilePath)
{
SolutionPath = solutionPath;
@@ -156,12 +177,38 @@ $@"<Project>
ProjectFilePath = projectFilePath;
}
+ public string TargetFramework { get; set; } = BuildVariables.DefaultNetCoreTargetFramework;
+
+ public string RuntimeIdentifier { get; set; } = string.Empty;
+
+ public string Configuration { get; set; } =
+#if DEBUG
+ "Debug";
+#else
+ "Release";
+#endif
+
+ /// <summary>
+ /// Razor-Temp\unique-id\project
+ /// </summary>
public string DirectoryPath { get; }
+ /// <summary>
+ /// Razor-Temp\unique-id\project\project.csproj
+ /// </summary>
public string ProjectFilePath { get;}
+ /// <summary>
+ /// Razor-Temp\unique-id\
+ /// </summary>
public string SolutionPath { get; }
+ public string IntermediateOutputDirectory => Path.Combine("obj", Configuration, TargetFramework, RuntimeIdentifier);
+
+ public string BuildOutputDirectory => Path.Combine("bin", Configuration, TargetFramework, RuntimeIdentifier);
+
+ public string PublishOutputDirectory => Path.Combine(BuildOutputDirectory, "publish");
+
public void Dispose()
{
if (PreserveWorkingDirectory)
@@ -210,5 +257,31 @@ $@"<Project>
throw new Exception($"File {fileName} could not be found in {baseDirectory} or its parent directories.");
}
+
+ internal void AddProjectFileContent(string content)
+ {
+ if (content == null)
+ {
+ throw new ArgumentNullException(nameof(content));
+ }
+
+ var existing = File.ReadAllText(ProjectFilePath);
+ var updated = existing.Replace("<!-- Test Placeholder -->", content);
+ File.WriteAllText(ProjectFilePath, updated);
+ }
+
+ internal void AddDirectoryBuildContent(string content)
+ {
+ if (content == null)
+ {
+ throw new ArgumentNullException(nameof(content));
+ }
+
+ var filepath = Path.Combine(DirectoryPath, "Directory.Build.props");
+
+ var existing = File.ReadAllText(filepath);
+ var updated = existing.Replace("<!-- Test Placeholder -->", content);
+ File.WriteAllText(filepath, updated);
+ }
}
}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/ServiceWorkerAssert.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/ServiceWorkerAssert.cs
new file mode 100644
index 0000000000..7585b5b76c
--- /dev/null
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/ServiceWorkerAssert.cs
@@ -0,0 +1,80 @@
+// 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.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.Json;
+using Microsoft.AspNetCore.Razor.Tasks;
+
+namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
+{
+ internal static class ServiceWorkerAssert
+ {
+ internal static void VerifyServiceWorkerFiles(MSBuildResult result, string outputDirectory, string serviceWorkerPath, string serviceWorkerContent, string assetsManifestPath)
+ {
+ // Check the expected files are there
+ var serviceWorkerResolvedPath = Assert.FileExists(result, outputDirectory, serviceWorkerPath);
+ var assetsManifestResolvedPath = Assert.FileExists(result, outputDirectory, assetsManifestPath);
+
+ // Check the service worker contains the expected content (which comes from the PublishedContent file)
+ Assert.FileContains(result, serviceWorkerResolvedPath, serviceWorkerContent);
+
+ // Check the assets manifest version was added to the published service worker
+ var assetsManifest = ReadServiceWorkerAssetsManifest(assetsManifestResolvedPath);
+ Assert.FileContains(result, serviceWorkerResolvedPath, $"/* Manifest version: {assetsManifest.version} */");
+
+ // Check the assets manifest contains correct entries for all static content we're publishing
+ var resolvedPublishDirectory = Path.Combine(result.Project.DirectoryPath, outputDirectory);
+ var outputFiles = Directory.GetFiles(resolvedPublishDirectory, "*", new EnumerationOptions { RecurseSubdirectories = true });
+ var assetsManifestHashesByUrl = (IReadOnlyDictionary<string, string>)assetsManifest.assets.ToDictionary(x => x.url, x => x.hash);
+ foreach (var filePath in outputFiles)
+ {
+ var relativePath = Path.GetRelativePath(resolvedPublishDirectory, filePath);
+
+ // We don't list compressed files in the SWAM, as these are transparent to the client,
+ // nor do we list the service worker itself or its assets manifest, as these don't need to be fetched in the same way
+ if (IsCompressedFile(relativePath)
+ || string.Equals(relativePath, serviceWorkerPath, StringComparison.Ordinal)
+ || string.Equals(relativePath, assetsManifestPath, StringComparison.Ordinal))
+ {
+ continue;
+ }
+
+ // Verify hash
+ var fileUrl = relativePath.Replace('\\', '/');
+ var expectedHash = ParseWebFormattedHash(assetsManifestHashesByUrl[fileUrl]);
+ Assert.Contains(fileUrl, assetsManifestHashesByUrl);
+ Assert.FileHashEquals(result, filePath, expectedHash);
+ }
+ }
+
+ private static string ParseWebFormattedHash(string webFormattedHash)
+ {
+ Assert.StartsWith("sha256-", webFormattedHash);
+ return webFormattedHash.Substring(7);
+ }
+
+ private static bool IsCompressedFile(string path)
+ {
+ switch (Path.GetExtension(path))
+ {
+ case ".br":
+ case ".gz":
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static AssetsManifestFile ReadServiceWorkerAssetsManifest(string assetsManifestResolvedPath)
+ {
+ var jsContents = File.ReadAllText(assetsManifestResolvedPath);
+ var jsonStart = jsContents.IndexOf("{");
+ var jsonLength = jsContents.LastIndexOf("}") - jsonStart + 1;
+ var json = jsContents.Substring(jsonStart, jsonLength);
+ return JsonSerializer.Deserialize<AssetsManifestFile>(json);
+ }
+ }
+}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildIncrementalismTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmBuildIncrementalismTest.cs
index 46a85cdea1..301d688e40 100644
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/BuildIncrementalismTest.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmBuildIncrementalismTest.cs
@@ -4,17 +4,18 @@
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Razor.Tasks;
using Xunit;
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
+namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
{
- public class BuildIncrementalismTest
+ public class WasmBuildIncrementalismTest
{
[Fact]
public async Task Build_WithLinker_IsIncremental()
{
// Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
var result = await MSBuildProcessManager.DotnetMSBuild(project);
Assert.BuildPassed(result);
@@ -43,14 +44,14 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
public async Task Build_SatelliteAssembliesFileIsPreserved()
{
// Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
File.Move(Path.Combine(project.DirectoryPath, "Resources.ja.resx.txt"), Path.Combine(project.DirectoryPath, "Resource.ja.resx"));
var result = await MSBuildProcessManager.DotnetMSBuild(project);
Assert.BuildPassed(result);
- var satelliteAssemblyCacheFile = Path.Combine(project.IntermediateOutputDirectory, "blazor", "blazor.satelliteasm.props");
- var satelliteAssemblyFile = Path.Combine(project.BuildOutputDirectory, "wwwroot", "_framework", "_bin", "ja", "standalone.resources.dll");
+ var satelliteAssemblyCacheFile = Path.Combine(project.IntermediateOutputDirectory, "blazor.satelliteasm.props");
+ var satelliteAssemblyFile = Path.Combine(project.BuildOutputDirectory, "wwwroot", "_framework", "ja", "blazorwasm.resources.dll");
var bootJson = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
// Assert
@@ -76,11 +77,11 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
Assert.FileExists(result, satelliteAssemblyCacheFile);
Assert.FileExists(result, satelliteAssemblyFile);
- var bootJsonFile = JsonSerializer.Deserialize<GenerateBlazorBootJson.BootJsonData>(File.ReadAllText(bootJson), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
+ var bootJsonFile = JsonSerializer.Deserialize<BootJsonData>(File.ReadAllText(bootJson), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
var satelliteResources = bootJsonFile.resources.satelliteResources;
var kvp = Assert.Single(satelliteResources);
Assert.Equal("ja", kvp.Key);
- Assert.Equal("ja/standalone.resources.dll", Assert.Single(kvp.Value).Key);
+ Assert.Equal("ja/blazorwasm.resources.dll", Assert.Single(kvp.Value).Key);
}
}
@@ -88,13 +89,13 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
public async Task Build_SatelliteAssembliesFileIsCreated_IfNewFileIsAdded()
{
// Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
var result = await MSBuildProcessManager.DotnetMSBuild(project);
Assert.BuildPassed(result);
- var satelliteAssemblyCacheFile = Path.Combine(project.IntermediateOutputDirectory, "blazor", "blazor.satelliteasm.props");
- var satelliteAssemblyFile = Path.Combine(project.BuildOutputDirectory, "wwwroot", "_framework", "_bin", "ja", "standalone.resources.dll");
+ var satelliteAssemblyCacheFile = Path.Combine(project.IntermediateOutputDirectory, "blazor.satelliteasm.props");
+ var satelliteAssemblyFile = Path.Combine(project.BuildOutputDirectory, "wwwroot", "_framework", "ja", "blazorwasm.resources.dll");
var bootJson = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
result = await MSBuildProcessManager.DotnetMSBuild(project);
@@ -102,7 +103,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
Assert.FileDoesNotExist(result, satelliteAssemblyCacheFile);
Assert.FileDoesNotExist(result, satelliteAssemblyFile);
- var bootJsonFile = JsonSerializer.Deserialize<GenerateBlazorBootJson.BootJsonData>(File.ReadAllText(bootJson), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
+ var bootJsonFile = JsonSerializer.Deserialize<BootJsonData>(File.ReadAllText(bootJson), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
var satelliteResources = bootJsonFile.resources.satelliteResources;
Assert.Null(satelliteResources);
@@ -112,26 +113,26 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
Assert.FileExists(result, satelliteAssemblyCacheFile);
Assert.FileExists(result, satelliteAssemblyFile);
- bootJsonFile = JsonSerializer.Deserialize<GenerateBlazorBootJson.BootJsonData>(File.ReadAllText(bootJson), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
+ bootJsonFile = JsonSerializer.Deserialize<BootJsonData>(File.ReadAllText(bootJson), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
satelliteResources = bootJsonFile.resources.satelliteResources;
var kvp = Assert.Single(satelliteResources);
Assert.Equal("ja", kvp.Key);
- Assert.Equal("ja/standalone.resources.dll", Assert.Single(kvp.Value).Key);
+ Assert.Equal("ja/blazorwasm.resources.dll", Assert.Single(kvp.Value).Key);
}
[Fact]
public async Task Build_SatelliteAssembliesFileIsDeleted_IfAllSatelliteFilesAreRemoved()
{
// Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
File.Move(Path.Combine(project.DirectoryPath, "Resources.ja.resx.txt"), Path.Combine(project.DirectoryPath, "Resource.ja.resx"));
var result = await MSBuildProcessManager.DotnetMSBuild(project);
Assert.BuildPassed(result);
- var satelliteAssemblyCacheFile = Path.Combine(project.IntermediateOutputDirectory, "blazor", "blazor.satelliteasm.props");
- var satelliteAssemblyFile = Path.Combine(project.BuildOutputDirectory, "wwwroot", "_framework", "_bin", "ja", "standalone.resources.dll");
+ var satelliteAssemblyCacheFile = Path.Combine(project.IntermediateOutputDirectory, "blazor.satelliteasm.props");
+ var satelliteAssemblyFile = Path.Combine(project.BuildOutputDirectory, "wwwroot", "_framework", "ja", "blazorwasm.resources.dll");
var bootJson = Path.Combine(project.DirectoryPath, project.BuildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
result = await MSBuildProcessManager.DotnetMSBuild(project);
@@ -139,11 +140,11 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
Assert.FileExists(result, satelliteAssemblyCacheFile);
Assert.FileExists(result, satelliteAssemblyFile);
- var bootJsonFile = JsonSerializer.Deserialize<GenerateBlazorBootJson.BootJsonData>(File.ReadAllText(bootJson), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
+ var bootJsonFile = JsonSerializer.Deserialize<BootJsonData>(File.ReadAllText(bootJson), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
var satelliteResources = bootJsonFile.resources.satelliteResources;
var kvp = Assert.Single(satelliteResources);
Assert.Equal("ja", kvp.Key);
- Assert.Equal("ja/standalone.resources.dll", Assert.Single(kvp.Value).Key);
+ Assert.Equal("ja/blazorwasm.resources.dll", Assert.Single(kvp.Value).Key);
File.Delete(Path.Combine(project.DirectoryPath, "Resource.ja.resx"));
@@ -151,7 +152,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
Assert.BuildPassed(result);
Assert.FileDoesNotExist(result, satelliteAssemblyCacheFile);
- bootJsonFile = JsonSerializer.Deserialize<GenerateBlazorBootJson.BootJsonData>(File.ReadAllText(bootJson), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
+ bootJsonFile = JsonSerializer.Deserialize<BootJsonData>(File.ReadAllText(bootJson), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
satelliteResources = bootJsonFile.resources.satelliteResources;
Assert.Null(satelliteResources);
}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmBuildIntegrationTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmBuildIntegrationTest.cs
new file mode 100644
index 0000000000..8788d9ce17
--- /dev/null
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmBuildIntegrationTest.cs
@@ -0,0 +1,242 @@
+// 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.IO;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Razor.Tasks;
+using Microsoft.AspNetCore.Testing;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
+{
+ public class WasmBuildIntegrationTest
+ {
+ private static readonly string DotNetJsFileName = $"dotnet.{BuildVariables.MicrosoftNETCoreAppRuntimeVersion}.js";
+
+ [Fact]
+ public async Task Build_Works()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project);
+
+ Assert.BuildPassed(result);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.webassembly.js");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "dotnet.wasm");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", DotNetJsFileName);
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "RazorClassLibrary.dll");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazorwasm.pdb");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "RazorClassLibrary.pdb");
+
+ var staticWebAssets = Assert.FileExists(result, buildOutputDirectory, "blazorwasm.StaticWebAssets.xml");
+ Assert.FileContains(result, staticWebAssets, Path.Combine(project.TargetFramework, "wwwroot"));
+ Assert.FileContains(result, staticWebAssets, Path.GetFullPath(Path.Combine(project.SolutionPath, "razorclasslibrary", "wwwroot")));
+ }
+
+ [Fact]
+ public async Task Build_InRelease_Works()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ project.Configuration = "Release";
+ var result = await MSBuildProcessManager.DotnetMSBuild(project);
+
+ Assert.BuildPassed(result);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.webassembly.js");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "dotnet.wasm");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", DotNetJsFileName);
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "RazorClassLibrary.dll");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazorwasm.pdb");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "RazorClassLibrary.pdb");
+
+ var staticWebAssets = Assert.FileExists(result, buildOutputDirectory, "blazorwasm.StaticWebAssets.xml");
+ Assert.FileContains(result, staticWebAssets, Path.Combine(project.TargetFramework, "wwwroot"));
+ Assert.FileContains(result, staticWebAssets, Path.GetFullPath(Path.Combine(project.SolutionPath, "razorclasslibrary", "wwwroot")));
+ }
+
+ [Fact]
+ public async Task Build_ProducesBootJsonDataWithExpectedContent()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ project.Configuration = "Debug";
+ var wwwroot = Path.Combine(project.DirectoryPath, "wwwroot");
+ File.WriteAllText(Path.Combine(wwwroot, "appsettings.json"), "Default settings");
+ File.WriteAllText(Path.Combine(wwwroot, "appsettings.development.json"), "Development settings");
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project);
+
+ Assert.BuildPassed(result);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ var bootJsonPath = Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ var bootJsonData = ReadBootJsonData(result, bootJsonPath);
+
+ var runtime = bootJsonData.resources.runtime.Keys;
+ Assert.Contains(DotNetJsFileName, runtime);
+ Assert.Contains("dotnet.wasm", runtime);
+
+ var assemblies = bootJsonData.resources.assembly.Keys;
+ Assert.Contains("blazorwasm.dll", assemblies);
+ Assert.Contains("RazorClassLibrary.dll", assemblies);
+ Assert.Contains("System.Text.Json.dll", assemblies);
+
+ var pdb = bootJsonData.resources.pdb.Keys;
+ Assert.Contains("blazorwasm.pdb", pdb);
+ Assert.Contains("RazorClassLibrary.pdb", pdb);
+
+ Assert.Null(bootJsonData.resources.satelliteResources);
+
+ Assert.Contains("appsettings.json", bootJsonData.config);
+ Assert.Contains("appsettings.development.json", bootJsonData.config);
+ }
+
+ [Fact]
+ public async Task Build_InRelease_ProducesBootJsonDataWithExpectedContent()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ project.Configuration = "Release";
+ var result = await MSBuildProcessManager.DotnetMSBuild(project);
+
+ Assert.BuildPassed(result);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ var bootJsonPath = Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ var bootJsonData = ReadBootJsonData(result, bootJsonPath);
+
+ var runtime = bootJsonData.resources.runtime.Keys;
+ Assert.Contains(DotNetJsFileName, runtime);
+ Assert.Contains("dotnet.wasm", runtime);
+
+ var assemblies = bootJsonData.resources.assembly.Keys;
+ Assert.Contains("blazorwasm.dll", assemblies);
+ Assert.Contains("RazorClassLibrary.dll", assemblies);
+ Assert.Contains("System.Text.Json.dll", assemblies);
+
+ var pdb = bootJsonData.resources.pdb.Keys;
+ Assert.Contains("blazorwasm.pdb", pdb);
+ Assert.Contains("RazorClassLibrary.pdb", pdb);
+ Assert.Null(bootJsonData.resources.satelliteResources);
+ }
+
+ [Fact(Skip = "https://github.com/dotnet/aspnetcore/issues/22975")]
+ public async Task Build_WithBlazorEnableTimeZoneSupportDisabled_DoesNotCopyTimeZoneInfo()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ project.Configuration = "Release";
+ project.AddProjectFileContent(
+@"
+<PropertyGroup>
+ <BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
+</PropertyGroup>");
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project);
+
+ Assert.BuildPassed(result);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ var bootJsonPath = Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ var bootJsonData = ReadBootJsonData(result, bootJsonPath);
+
+ var runtime = bootJsonData.resources.runtime.Keys;
+ Assert.Contains("dotnet.wasm", runtime);
+ Assert.DoesNotContain("dotnet.timezones.dat", runtime);
+
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", "dotnet.wasm");
+ Assert.FileDoesNotExist(result, buildOutputDirectory, "wwwroot", "_framework", "wasm", "dotnet.timezones.dat");
+ }
+
+ [Fact]
+ public async Task Build_Hosted_Works()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project);
+
+ Assert.BuildPassed(result);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ Assert.FileDoesNotExist(result, buildOutputDirectory, "wwwroot", "_framework", "_bin", "blazorwasm.dll");
+
+ var staticWebAssets = Assert.FileExists(result, buildOutputDirectory, "blazorhosted.StaticWebAssets.xml");
+ Assert.FileContains(result, staticWebAssets, Path.Combine("net5.0", "wwwroot"));
+ Assert.FileContains(result, staticWebAssets, Path.Combine("razorclasslibrary", "wwwroot"));
+ Assert.FileContains(result, staticWebAssets, Path.Combine("blazorwasm", "wwwroot"));
+ }
+
+ [Fact]
+ [QuarantinedTest]
+ public async Task Build_SatelliteAssembliesAreCopiedToBuildOutput()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
+ project.AddProjectFileContent(
+@"
+<PropertyGroup>
+ <DefineConstants>$(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies</DefineConstants>
+</PropertyGroup>
+<ItemGroup>
+ <ProjectReference Include=""..\classlibrarywithsatelliteassemblies\classlibrarywithsatelliteassemblies.csproj"" />
+</ItemGroup>");
+ var resxfileInProject = Path.Combine(project.DirectoryPath, "Resources.ja.resx.txt");
+ File.Move(resxfileInProject, Path.Combine(project.DirectoryPath, "Resource.ja.resx"));
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/restore");
+
+ Assert.BuildPassed(result);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "classlibrarywithsatelliteassemblies.dll");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "Microsoft.CodeAnalysis.CSharp.dll");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output.
+
+ var bootJsonPath = Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\"");
+ Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\"");
+ }
+
+ [Fact]
+ public async Task Build_WithCustomOutputPath_Works()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+
+ project.AddDirectoryBuildContent(
+@"<PropertyGroup>
+ <BaseOutputPath>$(MSBuildThisFileDirectory)build\bin\</BaseOutputPath>
+ <BaseIntermediateOutputPath>$(MSBuildThisFileDirectory)build\obj\</BaseIntermediateOutputPath>
+</PropertyGroup>");
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/restore");
+ Assert.BuildPassed(result);
+ }
+
+ private static BootJsonData ReadBootJsonData(MSBuildResult result, string path)
+ {
+ return JsonSerializer.Deserialize<BootJsonData>(
+ File.ReadAllText(Path.Combine(result.Project.DirectoryPath, path)),
+ new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
+ }
+ }
+}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmBuildLazyLoadTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmBuildLazyLoadTest.cs
new file mode 100644
index 0000000000..674d180c88
--- /dev/null
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmBuildLazyLoadTest.cs
@@ -0,0 +1,173 @@
+// 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.IO;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Razor.Tasks;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
+{
+ public class WasmBuildLazyLoadTest
+ {
+ [Fact]
+ public async Task Build_LazyLoadExplicitAssembly_Debug_Works()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ project.Configuration = "Debug";
+
+ project.AddProjectFileContent(
+@"
+<ItemGroup>
+ <BlazorWebAssemblyLazyLoad Include='RazorClassLibrary' />
+</ItemGroup>
+");
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ // Verify that a blazor.boot.json file has been created
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ // And that the assembly is in the output
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "RazorClassLibrary.dll");
+
+ var bootJson = ReadBootJsonData(result, Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json"));
+
+ // And that it has been labelled as a dynamic assembly in the boot.json
+ var dynamicAssemblies = bootJson.resources.dynamicAssembly;
+ var assemblies = bootJson.resources.assembly;
+
+ Assert.NotNull(dynamicAssemblies);
+ Assert.Contains("RazorClassLibrary.dll", dynamicAssemblies.Keys);
+ Assert.DoesNotContain("RazorClassLibrary.dll", assemblies.Keys);
+
+ // App assembly should not be lazy loaded
+ Assert.DoesNotContain("blazorwasm.dll", dynamicAssemblies.Keys);
+ Assert.Contains("blazorwasm.dll", assemblies.Keys);
+ }
+
+ [Fact]
+ public async Task Build_LazyLoadExplicitAssembly_Release_Works()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ project.Configuration = "Release";
+
+ project.AddProjectFileContent(
+@"
+<ItemGroup>
+ <BlazorWebAssemblyLazyLoad Include='RazorClassLibrary' />
+</ItemGroup>
+");
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ // Verify that a blazor.boot.json file has been created
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ // And that the assembly is in the output
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "RazorClassLibrary.dll");
+
+ var bootJson = ReadBootJsonData(result, Path.Combine(buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json"));
+
+ // And that it has been labelled as a dynamic assembly in the boot.json
+ var dynamicAssemblies = bootJson.resources.dynamicAssembly;
+ var assemblies = bootJson.resources.assembly;
+
+ Assert.NotNull(dynamicAssemblies);
+ Assert.Contains("RazorClassLibrary.dll", dynamicAssemblies.Keys);
+ Assert.DoesNotContain("RazorClassLibrary.dll", assemblies.Keys);
+
+ // App assembly should not be lazy loaded
+ Assert.DoesNotContain("blazorwasm.dll", dynamicAssemblies.Keys);
+ Assert.Contains("blazorwasm.dll", assemblies.Keys);
+ }
+
+ [Fact]
+ public async Task Publish_LazyLoadExplicitAssembly_Debug_Works()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ project.Configuration = "Debug";
+
+ project.AddProjectFileContent(
+@"
+<ItemGroup>
+ <BlazorWebAssemblyLazyLoad Include='RazorClassLibrary' />
+</ItemGroup>
+");
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
+
+ var publishDirectory = project.PublishOutputDirectory;
+
+ // Verify that a blazor.boot.json file has been created
+ Assert.FileExists(result, publishDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ // And that the assembly is in the output
+ Assert.FileExists(result, publishDirectory, "wwwroot", "_framework", "RazorClassLibrary.dll");
+
+ var bootJson = ReadBootJsonData(result, Path.Combine(publishDirectory, "wwwroot", "_framework", "blazor.boot.json"));
+
+ // And that it has been labelled as a dynamic assembly in the boot.json
+ var dynamicAssemblies = bootJson.resources.dynamicAssembly;
+ var assemblies = bootJson.resources.assembly;
+
+ Assert.NotNull(dynamicAssemblies);
+ Assert.Contains("RazorClassLibrary.dll", dynamicAssemblies.Keys);
+ Assert.DoesNotContain("RazorClassLibrary.dll", assemblies.Keys);
+
+ // App assembly should not be lazy loaded
+ Assert.DoesNotContain("blazorwasm.dll", dynamicAssemblies.Keys);
+ Assert.Contains("blazorwasm.dll", assemblies.Keys);
+ }
+
+ [Fact]
+ public async Task Publish_LazyLoadExplicitAssembly_Release_Works()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ project.Configuration = "Release";
+
+ project.AddProjectFileContent(
+@"
+<ItemGroup>
+ <BlazorWebAssemblyLazyLoad Include='RazorClassLibrary' />
+</ItemGroup>
+");
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
+
+ var publishDirectory = project.PublishOutputDirectory;
+
+ // Verify that a blazor.boot.json file has been created
+ Assert.FileExists(result, publishDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ // And that the assembly is in the output
+ Assert.FileExists(result, publishDirectory, "wwwroot", "_framework", "RazorClassLibrary.dll");
+
+ var bootJson = ReadBootJsonData(result, Path.Combine(publishDirectory, "wwwroot", "_framework", "blazor.boot.json"));
+
+ // And that it has been labelled as a dynamic assembly in the boot.json
+ var dynamicAssemblies = bootJson.resources.dynamicAssembly;
+ var assemblies = bootJson.resources.assembly;
+
+ Assert.NotNull(dynamicAssemblies);
+ Assert.Contains("RazorClassLibrary.dll", dynamicAssemblies.Keys);
+ Assert.DoesNotContain("RazorClassLibrary.dll", assemblies.Keys);
+
+ // App assembly should not be lazy loaded
+ Assert.DoesNotContain("blazorwasm.dll", dynamicAssemblies.Keys);
+ Assert.Contains("blazorwasm.dll", assemblies.Keys);
+ }
+
+ private static BootJsonData ReadBootJsonData(MSBuildResult result, string path)
+ {
+ return JsonSerializer.Deserialize<BootJsonData>(
+ File.ReadAllText(Path.Combine(result.Project.DirectoryPath, path)),
+ new JsonSerializerOptions(JsonSerializerDefaults.Web));
+ }
+ }
+}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmCompressionTests.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmCompressionTests.cs
new file mode 100644
index 0000000000..e308d78274
--- /dev/null
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmCompressionTests.cs
@@ -0,0 +1,165 @@
+// 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.IO;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
+{
+ public class WasmCompressionTests
+ {
+ [Fact]
+ public async Task Publish_UpdatesFilesWhenSourcesChange()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary" });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish");
+
+ Assert.BuildPassed(result);
+
+ // Act
+ var mainAppDll = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll");
+ var mainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll);
+ var mainAppCompressedDll = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll.br");
+ var mainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);
+
+ var blazorBootJson = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ var blazorBootJsonThumbPrint = FileThumbPrint.Create(blazorBootJson);
+ var blazorBootJsonCompressed = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazor.boot.json.br");
+ var blazorBootJsonCompressedThumbPrint = FileThumbPrint.Create(blazorBootJsonCompressed);
+
+ var programFile = Path.Combine(project.DirectoryPath, "..", "blazorwasm", "Program.cs");
+ var programFileContents = File.ReadAllText(programFile);
+ File.WriteAllText(programFile, programFileContents.Replace("args", "arguments"));
+
+ // Assert
+ result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish");
+ Assert.BuildPassed(result);
+ var newMainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll);
+ var newMainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);
+ var newBlazorBootJsonThumbPrint = FileThumbPrint.Create(blazorBootJson);
+ var newBlazorBootJsonCompressedThumbPrint = FileThumbPrint.Create(blazorBootJsonCompressed);
+
+ Assert.NotEqual(mainAppDllThumbPrint, newMainAppDllThumbPrint);
+ Assert.NotEqual(mainAppCompressedDllThumbPrint, newMainAppCompressedDllThumbPrint);
+
+ Assert.NotEqual(blazorBootJsonThumbPrint, newBlazorBootJsonThumbPrint);
+ Assert.NotEqual(blazorBootJsonCompressedThumbPrint, newBlazorBootJsonCompressedThumbPrint);
+ }
+
+ [Fact]
+ public async Task Publish_WithoutLinkerAndCompression_UpdatesFilesWhenSourcesChange()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary" });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish", args: "/p:BlazorWebAssemblyEnableLinking=false");
+
+ Assert.BuildPassed(result);
+
+ // Act
+ var mainAppDll = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll");
+ var mainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll);
+
+ var mainAppCompressedDll = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll.br");
+ var mainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);
+
+ var programFile = Path.Combine(project.DirectoryPath, "..", "blazorwasm", "Program.cs");
+ var programFileContents = File.ReadAllText(programFile);
+ File.WriteAllText(programFile, programFileContents.Replace("args", "arguments"));
+
+ // Assert
+ result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish", args: "/p:BlazorWebAssemblyEnableLinking=false");
+ Assert.BuildPassed(result);
+ var newMainAppDllThumbPrint = FileThumbPrint.Create(mainAppDll);
+ var newMainAppCompressedDllThumbPrint = FileThumbPrint.Create(mainAppCompressedDll);
+
+ Assert.NotEqual(mainAppDllThumbPrint, newMainAppDllThumbPrint);
+ Assert.NotEqual(mainAppCompressedDllThumbPrint, newMainAppCompressedDllThumbPrint);
+ }
+
+ [Fact]
+ public async Task Publish_WithLinkerAndCompression_IsIncremental()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary" });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish");
+
+ Assert.BuildPassed(result);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ // Act
+ var compressedFilesFolder = Path.Combine("..", "blazorwasm", project.IntermediateOutputDirectory, "brotli");
+ var thumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
+
+ // Assert
+ for (var i = 0; i < 3; i++)
+ {
+ result = await MSBuildProcessManager.DotnetMSBuild(project);
+ Assert.BuildPassed(result);
+
+ var newThumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
+ Assert.Equal(thumbPrint.Count, newThumbPrint.Count);
+ for (var j = 0; j < thumbPrint.Count; j++)
+ {
+ Assert.Equal(thumbPrint[j], newThumbPrint[j]);
+ }
+ }
+ }
+
+ [Fact]
+ public async Task Publish_WithoutLinkerAndCompression_IsIncremental()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary" });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish", args: "/p:BlazorWebAssemblyEnableLinking=false");
+
+ Assert.BuildPassed(result);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ // Act
+ var compressedFilesFolder = Path.Combine("..", "blazorwasm", project.IntermediateOutputDirectory, "brotli");
+ var thumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
+
+ // Assert
+ for (var i = 0; i < 3; i++)
+ {
+ result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/p:BlazorWebAssemblyEnableLinking=false");
+ Assert.BuildPassed(result);
+
+ var newThumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
+ Assert.Equal(thumbPrint.Count, newThumbPrint.Count);
+ for (var j = 0; j < thumbPrint.Count; j++)
+ {
+ Assert.Equal(thumbPrint[j], newThumbPrint[j]);
+ }
+ }
+ }
+
+ [Fact]
+ public async Task Publish_CompressesAllFrameworkFiles()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "publish");
+
+ Assert.BuildPassed(result);
+
+ var extensions = new[] { ".dll", ".js", ".pdb", ".wasm", ".map", ".json", ".dat" };
+
+ // Act
+ var frameworkFilesPath = Path.Combine(project.DirectoryPath, project.PublishOutputDirectory, "wwwroot", "_framework");
+
+ foreach (var file in Directory.EnumerateFiles(frameworkFilesPath, "*", new EnumerationOptions { RecurseSubdirectories = true, }))
+ {
+ var extension = Path.GetExtension(file);
+ if (extension != ".br" && extension != ".gz")
+ {
+ Assert.FileExists(result, file + ".br");
+ }
+ }
+ }
+ }
+}
diff --git a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/PublishIntegrationTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmPublishIntegrationTest.cs
index b4b34470ea..dfaec7c803 100644
--- a/src/Components/WebAssembly/Build/test/BuildIntegrationTests/PublishIntegrationTest.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmPublishIntegrationTest.cs
@@ -1,28 +1,27 @@
// 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.Collections.Generic;
using System.IO;
-using System.Linq;
+using System.IO.Compression;
using System.Text.Json;
using System.Threading.Tasks;
-using Microsoft.AspNetCore.Blazor.Build;
+using Microsoft.AspNetCore.Razor.Tasks;
using Microsoft.AspNetCore.Testing;
using Xunit;
using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary<string, string>;
-using static Microsoft.AspNetCore.Components.WebAssembly.Build.WebAssemblyRuntimePackage;
-using System.IO.Compression;
+using static Microsoft.AspNetCore.Razor.Design.IntegrationTests.ServiceWorkerAssert;
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
+namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
{
- public class PublishIntegrationTest
+ public class WasmPublishIntegrationTest
{
+ private static readonly string DotNetJsFileName = $"dotnet.{BuildVariables.MicrosoftNETCoreAppRuntimeVersion}.js";
+
[Fact]
public async Task Publish_WithDefaultSettings_Works()
{
// Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new [] { "razorclasslibrary", "LinkBaseToWebRoot" });
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary", "LinkBaseToWebRoot" });
project.Configuration = "Debug";
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
@@ -34,10 +33,10 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.webassembly.js");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", "dotnet.wasm");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", DotNetJsFileName);
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", DotNetJsFileName);
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
// Verify referenced static web assets
Assert.FileExists(result, blazorPublishDirectory, "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js");
@@ -61,31 +60,29 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
serviceWorkerContent: "// This is the production service worker",
assetsManifestPath: "custom-service-worker-assets.js");
-
- // When publishing without linker, we expect to have collation information present in mscorlib.dll
- Assert.AssemblyContainsResource(result, Path.Combine(blazorPublishDirectory, "_framework", "_bin", "mscorlib.dll"), "collation.cjkCHS.bin");
}
[Fact]
public async Task Publish_InRelease_Works()
{
// Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new [] { "razorclasslibrary", "LinkBaseToWebRoot" });
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary", "LinkBaseToWebRoot" });
project.Configuration = "Release";
- var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", "");
Assert.BuildPassed(result);
+
var publishDirectory = project.PublishOutputDirectory;
var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.webassembly.js");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", "dotnet.wasm");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", DotNetJsFileName);
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", DotNetJsFileName);
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
// Verify referenced static web assets
Assert.FileExists(result, blazorPublishDirectory, "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js");
@@ -103,38 +100,13 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
// Verify web.config
Assert.FileExists(result, publishDirectory, "web.config");
Assert.FileCountEquals(result, 1, publishDirectory, "*", SearchOption.TopDirectoryOnly);
-
- // When publishing with linker, we expect to have collation information present in mscorlib.dll
- Assert.AssemblyContainsResource(result, Path.Combine(blazorPublishDirectory, "_framework", "_bin", "mscorlib.dll"), "collation.cjkCHS.bin");
- }
-
- [Fact]
- public async Task Publish_LinkerEnabledAndBlazorWebAssemblyPreserveCollationDataSet_CollationInformationIsPreserved()
- {
- // Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
- project.Configuration = "Release";
- project.AddProjectFileContent(
-@"<PropertyGroup>
- <BlazorWebAssemblyPreserveCollationData>false</BlazorWebAssemblyPreserveCollationData>
-</PropertyGroup>");
- var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
-
- Assert.BuildPassed(result);
-
- var publishDirectory = project.PublishOutputDirectory;
-
- var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");
-
- // When publishing with BlazorWebAssemblyPreserveCollationData=false, collation information should be stripped out.
- Assert.AssemblyDoesNotContainResource(result, Path.Combine(blazorPublishDirectory, "_framework", "_bin", "mscorlib.dll"), "collation.cjkCHS.bin");
}
[Fact]
public async Task Publish_WithExistingWebConfig_Works()
{
// Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "LinkBaseToWebRoot" });
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary", "LinkBaseToWebRoot" });
project.Configuration = "Release";
var webConfigContents = "test webconfig contents";
@@ -155,7 +127,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
public async Task Publish_WithNoBuild_Works()
{
// Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Build");
Assert.BuildPassed(result);
@@ -169,10 +141,10 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.webassembly.js");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", "dotnet.wasm");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", DotNetJsFileName);
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", DotNetJsFileName);
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
// Verify static assets are in the publish directory
Assert.FileExists(result, blazorPublishDirectory, "index.html");
@@ -209,13 +181,13 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
}
[Fact]
- public async Task Publish_WithLinkOnBuildDisabled_Works()
+ public async Task Publish_WithTrimmingdDisabled_Works()
{
// Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new [] { "razorclasslibrary" });
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
project.AddProjectFileContent(
@"<PropertyGroup>
- <BlazorWebAssemblyEnableLinking>false</BlazorWebAssemblyEnableLinking>
+ <PublishTrimmed>false</PublishTrimmed>
</PropertyGroup>");
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
@@ -227,10 +199,14 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.webassembly.js");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", "dotnet.wasm");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", DotNetJsFileName);
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", DotNetJsFileName);
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
+
+ // Verify compression works
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.br"); //
// Verify static assets are in the publish directory
Assert.FileExists(result, blazorPublishDirectory, "index.html");
@@ -253,7 +229,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
public async Task Publish_SatelliteAssemblies_AreCopiedToBuildOutput()
{
// Arrange
- using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
project.AddProjectFileContent(
@"
<PropertyGroup>
@@ -270,49 +246,44 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
var publishDirectory = project.PublishOutputDirectory;
var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "Microsoft.CodeAnalysis.CSharp.dll");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output.
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "Microsoft.CodeAnalysis.CSharp.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output.
var bootJsonPath = Path.Combine(blazorPublishDirectory, "_framework", "blazor.boot.json");
Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\"");
Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\"");
VerifyBootManifestHashes(result, blazorPublishDirectory);
- VerifyServiceWorkerFiles(result, blazorPublishDirectory,
- serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
- serviceWorkerContent: "// This is the production service worker",
- assetsManifestPath: "custom-service-worker-assets.js");
}
[Fact]
[QuarantinedTest]
- public async Task Publish_HostedApp_WithLinkOnBuildTrue_Works()
+ public async Task Publish_HostedApp_DefaultSettings_Works()
{
// Arrange
- using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary", });
- project.TargetFramework = TestFacts.DefaultNetCoreTargetFramework;
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", });
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
- AddSiblingProjectFileContent(project, @"
-<PropertyGroup>
- <BlazorWebAssemblyEnableLinking>true</BlazorWebAssemblyEnableLinking>
-</PropertyGroup>");
-
Assert.BuildPassed(result);
var publishDirectory = project.PublishOutputDirectory;
// Make sure the main project exists
Assert.FileExists(result, publishDirectory, "blazorhosted.dll");
+
+ // Verification for https://github.com/dotnet/aspnetcore/issues/19926. Verify binaries for projects
+ // referenced by the Hosted project appear in the publish directory
Assert.FileExists(result, publishDirectory, "RazorClassLibrary.dll");
+ Assert.FileExists(result, publishDirectory, "blazorwasm.dll");
var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.webassembly.js");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", "dotnet.wasm");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", DotNetJsFileName);
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", DotNetJsFileName);
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
+
// Verify project references appear as static web assets
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "RazorClassLibrary.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll");
// Also verify project references to the server project appear in the publish output
Assert.FileExists(result, publishDirectory, "RazorClassLibrary.dll");
@@ -327,6 +298,13 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
Assert.FileExists(result, publishDirectory, "web.config");
VerifyBootManifestHashes(result, blazorPublishDirectory);
+
+ // Verify compression works
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.br");
+
VerifyServiceWorkerFiles(result, blazorPublishDirectory,
serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
serviceWorkerContent: "// This is the production service worker",
@@ -334,17 +312,82 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
}
[Fact]
- // Regression test for https://github.com/dotnet/aspnetcore/issues/18752
- public async Task Publish_HostedApp_WithLinkOnBuildFalse_Works()
+ public async Task Publish_HostedApp_ProducesBootJsonDataWithExpectedContent()
{
// Arrange
- using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary", });
- project.TargetFramework = TestFacts.DefaultNetCoreTargetFramework;
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", });
+ var wwwroot = Path.Combine(project.DirectoryPath, "..", "blazorwasm", "wwwroot");
+ File.WriteAllText(Path.Combine(wwwroot, "appsettings.json"), "Default settings");
+ File.WriteAllText(Path.Combine(wwwroot, "appsettings.development.json"), "Development settings");
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
+ Assert.BuildPassed(result);
+
+ var bootJsonPath = Path.Combine(project.PublishOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ var bootJsonData = ReadBootJsonData(result, bootJsonPath);
+
+ var runtime = bootJsonData.resources.runtime.Keys;
+ Assert.Contains(DotNetJsFileName, runtime);
+ Assert.Contains("dotnet.wasm", runtime);
+
+ var assemblies = bootJsonData.resources.assembly.Keys;
+ Assert.Contains("blazorwasm.dll", assemblies);
+ Assert.Contains("RazorClassLibrary.dll", assemblies);
+ Assert.Contains("System.Text.Json.dll", assemblies);
+
+ // No pdbs
+ Assert.Null(bootJsonData.resources.pdb);
+ Assert.Null(bootJsonData.resources.satelliteResources);
+
+ Assert.Contains("appsettings.json", bootJsonData.config);
+ Assert.Contains("appsettings.development.json", bootJsonData.config);
+ }
- AddSiblingProjectFileContent(project, @"
+ [Fact]
+ public async Task Publish_HostedApp_WithSatelliteAssemblies()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", "classlibrarywithsatelliteassemblies", });
+ var wasmProject = project.GetSibling("blazorwasm");
+
+ wasmProject.AddProjectFileContent(
+@"
<PropertyGroup>
- <BlazorWebAssemblyEnableLinking>false</BlazorWebAssemblyEnableLinking>
-</PropertyGroup>");
+ <DefineConstants>$(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies</DefineConstants>
+</PropertyGroup>
+<ItemGroup>
+ <ProjectReference Include=""..\classlibrarywithsatelliteassemblies\classlibrarywithsatelliteassemblies.csproj"" />
+</ItemGroup>");
+ var resxfileInProject = Path.Combine(wasmProject.DirectoryPath, "Resources.ja.resx.txt");
+ File.Move(resxfileInProject, Path.Combine(wasmProject.DirectoryPath, "Resource.ja.resx"));
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", "/restore");
+ Assert.BuildPassed(result);
+
+ var bootJsonPath = Path.Combine(project.PublishOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ var bootJsonData = ReadBootJsonData(result, bootJsonPath);
+
+ var publishOutputDirectory = project.PublishOutputDirectory;
+
+ Assert.FileExists(result, publishOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, publishOutputDirectory, "wwwroot", "_framework", "classlibrarywithsatelliteassemblies.dll");
+ Assert.FileExists(result, publishOutputDirectory, "wwwroot", "_framework", "Microsoft.CodeAnalysis.CSharp.dll");
+ Assert.FileExists(result, publishOutputDirectory, "wwwroot", "_framework", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output.
+
+ Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\"");
+ Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\"");
+ }
+
+ [Fact]
+ // Regression test for https://github.com/dotnet/aspnetcore/issues/18752
+ public async Task Publish_HostedApp_WithoutTrimming_Works()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", });
+ AddWasmProjectContent(project, @"
+ <PropertyGroup>
+ <PublishTrimmed>false</PublishTrimmed>
+ </PropertyGroup>");
// VS builds projects individually and then a publish with BuildDependencies=false, but building the main project is a close enough approximation for this test.
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Build");
@@ -361,16 +404,19 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
// Verification for https://github.com/dotnet/aspnetcore/issues/19926. Verify binaries for projects
// referenced by the Hosted project appear in the publish directory
Assert.FileExists(result, publishDirectory, "RazorClassLibrary.dll");
- Assert.FileExists(result, publishDirectory, "standalone.dll");
+ Assert.FileExists(result, publishDirectory, "blazorwasm.dll");
var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.webassembly.js");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", "dotnet.wasm");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", DotNetJsFileName);
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "RazorClassLibrary.dll");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", DotNetJsFileName);
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
+
+ // Verify project references appear as static web assets
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll");
+ // Also verify project references to the server project appear in the publish output
+ Assert.FileExists(result, publishDirectory, "RazorClassLibrary.dll");
// Verify static assets are in the publish directory
Assert.FileExists(result, blazorPublishDirectory, "index.html");
@@ -379,26 +425,28 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js");
Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "styles.css");
- // Verify static assets are in the publish directory
- Assert.FileExists(result, blazorPublishDirectory, "index.html");
-
// Verify web.config
Assert.FileExists(result, publishDirectory, "web.config");
VerifyBootManifestHashes(result, blazorPublishDirectory);
+
+ // Verify compression works
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.br");
+
VerifyServiceWorkerFiles(result, blazorPublishDirectory,
serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
serviceWorkerContent: "// This is the production service worker",
assetsManifestPath: "custom-service-worker-assets.js");
-
- }
+ }
[Fact]
public async Task Publish_HostedApp_WithNoBuild_Works()
{
// Arrange
- using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary", });
- project.TargetFramework = TestFacts.DefaultNetCoreTargetFramework;
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", });
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Build");
Assert.BuildPassed(result);
@@ -411,11 +459,10 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.webassembly.js");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", "dotnet.wasm");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", DotNetJsFileName);
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", DotNetJsFileName);
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
// Verify static assets are in the publish directory
Assert.FileExists(result, blazorPublishDirectory, "index.html");
@@ -439,8 +486,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
{
// Simulates publishing the same way VS does by setting BuildProjectReferences=false.
// Arrange
- using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary", });
- project.TargetFramework = TestFacts.DefaultNetCoreTargetFramework;
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", });
project.Configuration = "Release";
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Build", "/p:BuildInsideVisualStudio=true");
@@ -454,11 +500,10 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.webassembly.js");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", "dotnet.wasm");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "wasm", DotNetJsFileName);
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "standalone.dll");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", DotNetJsFileName);
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
// Verify static assets are in the publish directory
Assert.FileExists(result, blazorPublishDirectory, "index.html");
@@ -467,6 +512,12 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js");
Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "styles.css");
+ // Verify compression works
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.br");
+
// Verify web.config
Assert.FileExists(result, publishDirectory, "web.config");
@@ -484,26 +535,24 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
{
// Simulates publishing the same way VS does by setting BuildProjectReferences=false.
// Arrange
- var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "standalone", "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
- project.TargetFramework = TestFacts.DefaultNetCoreTargetFramework;
- project.Configuration = "Release";
- var standaloneProjectDirectory = Path.Combine(project.DirectoryPath, "..", "standalone");
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
+ var blazorwasmProjectDirectory = Path.Combine(project.DirectoryPath, "..", "blazorwasm");
- // Setup the standalone app to have it's own satellite assemblies as well as transitively imported satellite assemblies.
- var resxfileInProject = Path.Combine(standaloneProjectDirectory , "Resources.ja.resx.txt");
- File.Move(resxfileInProject, Path.Combine(standaloneProjectDirectory, "Resource.ja.resx"));
+ // Setup the blazorwasm app to have it's own satellite assemblies as well as transitively imported satellite assemblies.
+ var resxfileInProject = Path.Combine(blazorwasmProjectDirectory, "Resources.ja.resx.txt");
+ File.Move(resxfileInProject, Path.Combine(blazorwasmProjectDirectory, "Resource.ja.resx"));
- var standaloneProjFile = Path.Combine(standaloneProjectDirectory, "standalone.csproj");
- var existing = File.ReadAllText(standaloneProjFile);
+ var blazorwasmProjFile = Path.Combine(blazorwasmProjectDirectory, "blazorwasm.csproj");
+ var existing = File.ReadAllText(blazorwasmProjFile);
var updatedContent = @"
-<PropertyGroup>
- <DefineConstants>$(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies</DefineConstants>
-</PropertyGroup>
-<ItemGroup>
- <ProjectReference Include=""..\classlibrarywithsatelliteassemblies\classlibrarywithsatelliteassemblies.csproj"" />
-</ItemGroup>";
+ <PropertyGroup>
+ <DefineConstants>$(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies</DefineConstants>
+ </PropertyGroup>
+ <ItemGroup>
+ <ProjectReference Include=""..\classlibrarywithsatelliteassemblies\classlibrarywithsatelliteassemblies.csproj"" />
+ </ItemGroup>";
var updated = existing.Replace("<!-- Test Placeholder -->", updatedContent);
- File.WriteAllText(standaloneProjFile, updated);
+ File.WriteAllText(blazorwasmProjFile, updated);
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Build", $"/restore");
@@ -517,11 +566,11 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "ja", "standalone.resources.dll");
- Assert.FileExists(result, blazorPublishDirectory, "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.resources.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "ja", "blazorwasm.resources.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "fr", "Microsoft.CodeAnalysis.resources.dll");
var bootJson = Path.Combine(project.DirectoryPath, blazorPublishDirectory, "_framework", "blazor.boot.json");
- var bootJsonFile = JsonSerializer.Deserialize<GenerateBlazorBootJson.BootJsonData>(File.ReadAllText(bootJson), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
+ var bootJsonFile = JsonSerializer.Deserialize<BootJsonData>(File.ReadAllText(bootJson), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
var satelliteResources = bootJsonFile.resources.satelliteResources;
Assert.Contains("es-ES", satelliteResources.Keys);
@@ -529,7 +578,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
Assert.Contains("fr", satelliteResources.Keys);
Assert.Contains("fr/Microsoft.CodeAnalysis.CSharp.resources.dll", satelliteResources["fr"].Keys);
Assert.Contains("ja", satelliteResources.Keys);
- Assert.Contains("ja/standalone.resources.dll", satelliteResources["ja"].Keys);
+ Assert.Contains("ja/blazorwasm.resources.dll", satelliteResources["ja"].Keys);
VerifyServiceWorkerFiles(result, blazorPublishDirectory,
serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
@@ -537,9 +586,64 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
assetsManifestPath: "custom-service-worker-assets.js");
}
- private static void AddSiblingProjectFileContent(ProjectDirectory project, string content)
+ [Fact]
+ public async Task Publish_HostedApp_WithRid_Works()
{
- var path = Path.Combine(project.SolutionPath, "standalone", "standalone.csproj");
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorhosted-rid", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", });
+ project.RuntimeIdentifier = "linux-x64";
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
+
+ Assert.BuildPassed(result);
+
+ var publishDirectory = project.PublishOutputDirectory;
+ // Make sure the main project exists
+ Assert.FileExists(result, publishDirectory, "blazorhosted-rid.dll");
+ Assert.FileExists(result, publishDirectory, "libhostfxr.so"); // Verify that we're doing a self-contained deployment
+
+ Assert.FileExists(result, publishDirectory, "RazorClassLibrary.dll");
+ Assert.FileExists(result, publishDirectory, "blazorwasm.dll");
+
+ var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.webassembly.js");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", DotNetJsFileName);
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
+
+ // Verify project references appear as static web assets
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll");
+ // Also verify project references to the server project appear in the publish output
+ Assert.FileExists(result, publishDirectory, "RazorClassLibrary.dll");
+
+ // Verify static assets are in the publish directory
+ Assert.FileExists(result, blazorPublishDirectory, "index.html");
+
+ // Verify static web assets from referenced projects are copied.
+ Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "wwwroot", "exampleJsInterop.js");
+ Assert.FileExists(result, publishDirectory, "wwwroot", "_content", "RazorClassLibrary", "styles.css");
+
+ // Verify web.config
+ Assert.FileExists(result, publishDirectory, "web.config");
+
+ VerifyBootManifestHashes(result, blazorPublishDirectory);
+
+ // Verify compression works
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll.br");
+ Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.br");
+
+ VerifyServiceWorkerFiles(result, blazorPublishDirectory,
+ serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
+ serviceWorkerContent: "// This is the production service worker",
+ assetsManifestPath: "custom-service-worker-assets.js");
+ }
+
+ private static void AddWasmProjectContent(ProjectDirectory project, string content)
+ {
+ var path = Path.Combine(project.SolutionPath, "blazorwasm", "blazorwasm.csproj");
var existing = File.ReadAllText(path);
var updated = existing.Replace("<!-- Test Placeholder -->", content);
File.WriteAllText(path, updated);
@@ -555,102 +659,43 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
{
var bootManifestResolvedPath = Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazor.boot.json");
var bootManifestJson = File.ReadAllText(bootManifestResolvedPath);
- var bootManifest = JsonSerializer.Deserialize<GenerateBlazorBootJson.BootJsonData>(bootManifestJson);
+ var bootManifest = JsonSerializer.Deserialize<BootJsonData>(bootManifestJson);
- VerifyBootManifestHashes(result, blazorPublishDirectory, bootManifest.resources.assembly, r => $"_framework/_bin/{r}");
- VerifyBootManifestHashes(result, blazorPublishDirectory, bootManifest.resources.runtime, r => $"_framework/wasm/{r}");
+ VerifyBootManifestHashes(result, blazorPublishDirectory, bootManifest.resources.assembly);
+ VerifyBootManifestHashes(result, blazorPublishDirectory, bootManifest.resources.runtime);
if (bootManifest.resources.pdb != null)
{
- VerifyBootManifestHashes(result, blazorPublishDirectory, bootManifest.resources.pdb, r => $"_framework/_bin/{r}");
+ VerifyBootManifestHashes(result, blazorPublishDirectory, bootManifest.resources.pdb);
}
if (bootManifest.resources.satelliteResources != null)
{
foreach (var resourcesForCulture in bootManifest.resources.satelliteResources.Values)
{
- VerifyBootManifestHashes(result, blazorPublishDirectory, resourcesForCulture, r => $"_framework/_bin/{r}");
+ VerifyBootManifestHashes(result, blazorPublishDirectory, resourcesForCulture);
}
}
- }
- private static void VerifyBootManifestHashes(MSBuildResult result, string blazorPublishDirectory, ResourceHashesByNameDictionary resources, Func<string, string> relativePathFunc)
- {
- foreach (var (name, hash) in resources)
+ static void VerifyBootManifestHashes(MSBuildResult result, string blazorPublishDirectory, ResourceHashesByNameDictionary resources)
{
- var relativePath = Path.Combine(blazorPublishDirectory, relativePathFunc(name));
- Assert.FileHashEquals(result, relativePath, ParseWebFormattedHash(hash));
- }
- }
-
- private static void VerifyServiceWorkerFiles(MSBuildResult result, string blazorPublishDirectory, string serviceWorkerPath, string serviceWorkerContent, string assetsManifestPath)
- {
- // Check the expected files are there
- var serviceWorkerResolvedPath = Assert.FileExists(result, blazorPublishDirectory, serviceWorkerPath);
- var assetsManifestResolvedPath = Assert.FileExists(result, blazorPublishDirectory, assetsManifestPath);
-
- // Check the service worker contains the expected content (which comes from the PublishedContent file)
- Assert.FileContains(result, serviceWorkerResolvedPath, serviceWorkerContent);
-
- // Check the assets manifest version was added to the published service worker
- var assetsManifest = ReadServiceWorkerAssetsManifest(assetsManifestResolvedPath);
- Assert.FileContains(result, serviceWorkerResolvedPath, $"/* Manifest version: {assetsManifest.version} */");
-
- // Check the assets manifest contains correct entries for all static content we're publishing
- var resolvedPublishDirectory = Path.Combine(result.Project.DirectoryPath, blazorPublishDirectory);
- var publishedStaticFiles = Directory.GetFiles(resolvedPublishDirectory, "*", new EnumerationOptions { RecurseSubdirectories = true });
- var assetsManifestHashesByUrl = (IReadOnlyDictionary<string, string>)assetsManifest.assets.ToDictionary(x => x.url, x => x.hash);
- foreach (var publishedFilePath in publishedStaticFiles)
- {
- var publishedFileRelativePath = Path.GetRelativePath(resolvedPublishDirectory, publishedFilePath);
-
- // We don't list compressed files in the SWAM, as these are transparent to the client,
- // nor do we list the service worker itself or its assets manifest, as these don't need to be fetched in the same way
- if (IsCompressedFile(publishedFileRelativePath)
- || string.Equals(publishedFileRelativePath, serviceWorkerPath, StringComparison.Ordinal)
- || string.Equals(publishedFileRelativePath, assetsManifestPath, StringComparison.Ordinal))
+ foreach (var (name, hash) in resources)
{
- continue;
+ var relativePath = Path.Combine(blazorPublishDirectory, "_framework", name);
+ Assert.FileHashEquals(result, relativePath, ParseWebFormattedHash(hash));
}
-
- // Verify hash
- var publishedFileUrl = publishedFileRelativePath.Replace('\\', '/');
- var expectedHash = ParseWebFormattedHash(assetsManifestHashesByUrl[publishedFileUrl]);
- Assert.Contains(publishedFileUrl, assetsManifestHashesByUrl);
- Assert.FileHashEquals(result, publishedFilePath, expectedHash);
}
- }
-
- private static string ParseWebFormattedHash(string webFormattedHash)
- {
- Assert.StartsWith("sha256-", webFormattedHash);
- return webFormattedHash.Substring(7);
- }
- private static bool IsCompressedFile(string path)
- {
- switch (Path.GetExtension(path))
+ static string ParseWebFormattedHash(string webFormattedHash)
{
- case ".br":
- case ".gz":
- return true;
- default:
- return false;
+ Assert.StartsWith("sha256-", webFormattedHash);
+ return webFormattedHash.Substring(7);
}
}
- private static GenerateServiceWorkerAssetsManifest.AssetsManifestFile ReadServiceWorkerAssetsManifest(string assetsManifestResolvedPath)
- {
- var jsContents = File.ReadAllText(assetsManifestResolvedPath);
- var jsonStart = jsContents.IndexOf("{");
- var jsonLength = jsContents.LastIndexOf("}") - jsonStart + 1;
- var json = jsContents.Substring(jsonStart, jsonLength);
- return JsonSerializer.Deserialize<GenerateServiceWorkerAssetsManifest.AssetsManifestFile>(json);
- }
-
- private static GenerateBlazorBootJson.BootJsonData ReadBootJsonData(MSBuildResult result, string path)
+ private static BootJsonData ReadBootJsonData(MSBuildResult result, string path)
{
- return JsonSerializer.Deserialize<GenerateBlazorBootJson.BootJsonData>(
+ return JsonSerializer.Deserialize<BootJsonData>(
File.ReadAllText(Path.Combine(result.Project.DirectoryPath, path)),
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmPwaManifestTests.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmPwaManifestTests.cs
new file mode 100644
index 0000000000..9bf091533b
--- /dev/null
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/Wasm/WasmPwaManifestTests.cs
@@ -0,0 +1,211 @@
+// 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.IO;
+using System.Linq;
+using System.Text.Json;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Xunit;
+using static Microsoft.AspNetCore.Razor.Design.IntegrationTests.ServiceWorkerAssert;
+
+
+namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
+{
+ public class WasmPwaManifestTests
+ {
+ private static readonly string DotNetJsFileName = $"dotnet.{BuildVariables.MicrosoftNETCoreAppRuntimeVersion}.js";
+
+ [Fact]
+ public async Task Build_ServiceWorkerAssetsManifest_Works()
+ {
+ // Arrange
+ var expectedExtensions = new[] { ".dll", ".pdb", ".js", ".wasm" };
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/p:ServiceWorkerAssetsManifest=service-worker-assets.js");
+
+ Assert.BuildPassed(result);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "dotnet.wasm");
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", DotNetJsFileName);
+ Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll");
+
+ var staticWebAssets = Assert.FileExists(result, buildOutputDirectory, "blazorwasm.StaticWebAssets.xml");
+ Assert.FileContains(result, staticWebAssets, Path.Combine(project.TargetFramework, "wwwroot"));
+
+ var serviceWorkerAssetsManifest = Assert.FileExists(result, buildOutputDirectory, "wwwroot", "service-worker-assets.js");
+ // Trim prefix 'self.assetsManifest = ' and suffix ';'
+ var manifestContents = File.ReadAllText(serviceWorkerAssetsManifest).TrimEnd()[22..^1];
+
+ var manifestContentsJson = JsonDocument.Parse(manifestContents);
+ Assert.True(manifestContentsJson.RootElement.TryGetProperty("assets", out var assets));
+ Assert.Equal(JsonValueKind.Array, assets.ValueKind);
+
+ var entries = assets.EnumerateArray().Select(e => e.GetProperty("url").GetString()).OrderBy(e => e).ToArray();
+ Assert.All(entries, e => expectedExtensions.Contains(Path.GetExtension(e)));
+
+ VerifyServiceWorkerFiles(result,
+ Path.Combine(buildOutputDirectory, "wwwroot"),
+ serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
+ serviceWorkerContent: "// This is the development service worker",
+ assetsManifestPath: "service-worker-assets.js");
+ }
+
+ [Fact]
+ public async Task Build_HostedAppWithServiceWorker_Works()
+ {
+ // Arrange
+ var expectedExtensions = new[] { ".dll", ".pdb", ".js", ".wasm" };
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary" });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project);
+
+ Assert.BuildPassed(result);
+
+ var wasmProject = project.GetSibling("blazorwasm");
+ var buildOutputDirectory = Path.Combine(wasmProject.DirectoryPath, wasmProject.BuildOutputDirectory);
+
+ var staticWebAssets = Assert.FileExists(result, buildOutputDirectory, "blazorwasm.StaticWebAssets.xml");
+ Assert.FileContains(result, staticWebAssets, Path.Combine(project.TargetFramework, "wwwroot"));
+
+ var serviceWorkerAssetsManifest = Assert.FileExists(result, buildOutputDirectory, "wwwroot", "custom-service-worker-assets.js");
+ // Trim prefix 'self.assetsManifest = ' and suffix ';'
+ var manifestContents = File.ReadAllText(serviceWorkerAssetsManifest).TrimEnd()[22..^1];
+
+ var manifestContentsJson = JsonDocument.Parse(manifestContents);
+ Assert.True(manifestContentsJson.RootElement.TryGetProperty("assets", out var assets));
+ Assert.Equal(JsonValueKind.Array, assets.ValueKind);
+
+ var entries = assets.EnumerateArray().Select(e => e.GetProperty("url").GetString()).OrderBy(e => e).ToArray();
+ Assert.All(entries, e => expectedExtensions.Contains(Path.GetExtension(e)));
+ }
+
+ [Fact]
+ public async Task PublishWithPWA_ProducesAssets()
+ {
+ // Arrange
+ var expectedExtensions = new[] { ".dll", ".pdb", ".js", ".wasm" };
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "Publish");
+
+ Assert.BuildPassed(result);
+
+ var publishOutputDirectory = project.PublishOutputDirectory;
+
+ var serviceWorkerAssetsManifest = Assert.FileExists(result, publishOutputDirectory, "wwwroot", "custom-service-worker-assets.js");
+ // Trim prefix 'self.assetsManifest = ' and suffix ';'
+ var manifestContents = File.ReadAllText(serviceWorkerAssetsManifest).TrimEnd()[22..^1];
+
+ var manifestContentsJson = JsonDocument.Parse(manifestContents);
+ Assert.True(manifestContentsJson.RootElement.TryGetProperty("assets", out var assets));
+ Assert.Equal(JsonValueKind.Array, assets.ValueKind);
+
+ var entries = assets.EnumerateArray().Select(e => e.GetProperty("url").GetString()).OrderBy(e => e).ToArray();
+ Assert.All(entries, e => expectedExtensions.Contains(Path.GetExtension(e)));
+
+ var serviceWorkerFile = Path.Combine(publishOutputDirectory, "wwwroot", "serviceworkers", "my-service-worker.js");
+ Assert.FileContainsLine(result, serviceWorkerFile, "// This is the production service worker");
+ }
+
+ [Fact]
+ public async Task PublishHostedWithPWA_ProducesAssets()
+ {
+ // Arrange
+ var expectedExtensions = new[] { ".dll", ".pdb", ".js", ".wasm" };
+ using var project = ProjectDirectory.Create("blazorhosted", additionalProjects: new[] { "blazorwasm", "razorclasslibrary" });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, target: "Publish");
+
+ Assert.BuildPassed(result);
+
+ var publishOutputDirectory = project.PublishOutputDirectory;
+
+ var serviceWorkerAssetsManifest = Assert.FileExists(result, publishOutputDirectory, "wwwroot", "custom-service-worker-assets.js");
+ // Trim prefix 'self.assetsManifest = ' and suffix ';'
+ var manifestContents = File.ReadAllText(serviceWorkerAssetsManifest).TrimEnd()[22..^1];
+
+ var manifestContentsJson = JsonDocument.Parse(manifestContents);
+ Assert.True(manifestContentsJson.RootElement.TryGetProperty("assets", out var assets));
+ Assert.Equal(JsonValueKind.Array, assets.ValueKind);
+
+ var entries = assets.EnumerateArray().Select(e => e.GetProperty("url").GetString()).OrderBy(e => e).ToArray();
+ Assert.All(entries, e => expectedExtensions.Contains(Path.GetExtension(e)));
+
+ var serviceWorkerFile = Path.Combine(publishOutputDirectory, "wwwroot", "serviceworkers", "my-service-worker.js");
+ Assert.FileContainsLine(result, serviceWorkerFile, "// This is the production service worker");
+ }
+
+ [Fact]
+ public async Task Publish_UpdatesServiceWorkerVersionHash_WhenSourcesChange()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args: "/bl:initial.binlog /p:ServiceWorkerAssetsManifest=service-worker-assets.js");
+
+ Assert.BuildPassed(result);
+
+ var publishOutputDirectory = project.PublishOutputDirectory;
+
+ var serviceWorkerFile = Assert.FileExists(result, publishOutputDirectory, "wwwroot", "serviceworkers", "my-service-worker.js");
+ var version = File.ReadAllLines(serviceWorkerFile).Last();
+ var match = Regex.Match(version, "\\/\\* Manifest version: (.{8}) \\*\\/");
+ Assert.True(match.Success);
+ Assert.Equal(2, match.Groups.Count);
+ Assert.NotNull(match.Groups[1].Value);
+ var capture = match.Groups[1].Value;
+
+ // Act
+ var cssFile = Path.Combine(project.DirectoryPath, "LinkToWebRoot", "css", "app.css");
+ File.WriteAllText(cssFile, ".updated { }");
+
+ // Assert
+ result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args: "/bl:updated.binlog /p:ServiceWorkerAssetsManifest=service-worker-assets.js");
+
+ Assert.BuildPassed(result);
+
+ var updatedVersion = File.ReadAllLines(serviceWorkerFile).Last();
+ var updatedMatch = Regex.Match(updatedVersion, "\\/\\* Manifest version: (.{8}) \\*\\/");
+ Assert.True(updatedMatch.Success);
+ Assert.Equal(2, updatedMatch.Groups.Count);
+ Assert.NotNull(updatedMatch.Groups[1].Value);
+ var updatedCapture = updatedMatch.Groups[1].Value;
+
+ Assert.NotEqual(capture, updatedCapture);
+ }
+
+ [Fact]
+ public async Task Publish_DeterministicAcrossBuilds_WhenNoSourcesChange()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args: "/bl:initial.binlog /p:ServiceWorkerAssetsManifest=service-worker-assets.js");
+
+ Assert.BuildPassed(result);
+
+ var publishOutputDirectory = project.PublishOutputDirectory;
+
+ var serviceWorkerFile = Assert.FileExists(result, publishOutputDirectory, "wwwroot", "serviceworkers", "my-service-worker.js");
+ var version = File.ReadAllLines(serviceWorkerFile).Last();
+ var match = Regex.Match(version, "\\/\\* Manifest version: (.{8}) \\*\\/");
+ Assert.True(match.Success, $"No match found for manifest version regex in line: {version}");
+ Assert.Equal(2, match.Groups.Count);
+ Assert.NotNull(match.Groups[1].Value);
+ var capture = match.Groups[1].Value;
+
+ // Act && Assert
+ result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args: "/bl:updated.binlog /p:ServiceWorkerAssetsManifest=service-worker-assets.js");
+
+ Assert.BuildPassed(result);
+
+ var updatedVersion = File.ReadAllLines(serviceWorkerFile).Last();
+ var updatedMatch = Regex.Match(updatedVersion, "\\/\\* Manifest version: (.{8}) \\*\\/");
+ Assert.True(updatedMatch.Success);
+ Assert.Equal(2, updatedMatch.Groups.Count);
+ Assert.NotNull(updatedMatch.Groups[1].Value);
+ var updatedCapture = updatedMatch.Groups[1].Value;
+
+ Assert.Equal(capture, updatedCapture);
+ }
+ }
+}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/AssetsManifestFile.cs b/src/Razor/Microsoft.NET.Sdk.Razor/src/AssetsManifestFile.cs
new file mode 100644
index 0000000000..34dde41812
--- /dev/null
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/AssetsManifestFile.cs
@@ -0,0 +1,33 @@
+// 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.Razor.Tasks
+{
+#pragma warning disable IDE1006 // Naming Styles
+ public class AssetsManifestFile
+ {
+ /// <summary>
+ /// Gets or sets a version string.
+ /// </summary>
+ public string version { get; set; }
+
+ /// <summary>
+ /// Gets or sets the assets. Keys are URLs; values are base-64-formatted SHA256 content hashes.
+ /// </summary>
+ public AssetsManifestFileEntry[] assets { get; set; }
+ }
+
+ public class AssetsManifestFileEntry
+ {
+ /// <summary>
+ /// Gets or sets the asset URL. Normally this will be relative to the application's base href.
+ /// </summary>
+ public string url { get; set; }
+
+ /// <summary>
+ /// Gets or sets the file content hash. This should be the base-64-formatted SHA256 value.
+ /// </summary>
+ public string hash { get; set; }
+ }
+#pragma warning restore IDE1006 // Naming Styles
+}
diff --git a/src/Components/WebAssembly/Build/src/Tasks/BlazorReadSatelliteAssemblyFile.cs b/src/Razor/Microsoft.NET.Sdk.Razor/src/BlazorReadSatelliteAssemblyFile.cs
index 18a3fc8214..f2f95dbf26 100644
--- a/src/Components/WebAssembly/Build/src/Tasks/BlazorReadSatelliteAssemblyFile.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/BlazorReadSatelliteAssemblyFile.cs
@@ -6,7 +6,7 @@ using System.Xml.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
+namespace Microsoft.AspNetCore.Razor.Tasks
{
public class BlazorReadSatelliteAssemblyFile : Task
{
diff --git a/src/Components/WebAssembly/Build/src/Tasks/BlazorWriteSatelliteAssemblyFile.cs b/src/Razor/Microsoft.NET.Sdk.Razor/src/BlazorWriteSatelliteAssemblyFile.cs
index e1e6a8150e..da07cf6d00 100644
--- a/src/Components/WebAssembly/Build/src/Tasks/BlazorWriteSatelliteAssemblyFile.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/BlazorWriteSatelliteAssemblyFile.cs
@@ -7,7 +7,7 @@ using System.Xml.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
+namespace Microsoft.AspNetCore.Razor.Tasks
{
public class BlazorWriteSatelliteAssemblyFile : Task
{
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/BootJsonData.cs b/src/Razor/Microsoft.NET.Sdk.Razor/src/BootJsonData.cs
new file mode 100644
index 0000000000..0952070c8d
--- /dev/null
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/BootJsonData.cs
@@ -0,0 +1,85 @@
+// 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.Collections.Generic;
+using System.Runtime.Serialization;
+using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary<string, string>;
+
+namespace Microsoft.AspNetCore.Razor.Tasks
+{
+#pragma warning disable IDE1006 // Naming Styles
+ /// <summary>
+ /// Defines the structure of a Blazor boot JSON file
+ /// </summary>
+ public class BootJsonData
+ {
+ /// <summary>
+ /// Gets the name of the assembly with the application entry point
+ /// </summary>
+ public string entryAssembly { get; set; }
+
+ /// <summary>
+ /// Gets the set of resources needed to boot the application. This includes the transitive
+ /// closure of .NET assemblies (including the entrypoint assembly), the dotnet.wasm file,
+ /// and any PDBs to be loaded.
+ ///
+ /// Within <see cref="ResourceHashesByNameDictionary"/>, dictionary keys are resource names,
+ /// and values are SHA-256 hashes formatted in prefixed base-64 style (e.g., 'sha256-abcdefg...')
+ /// as used for subresource integrity checking.
+ /// </summary>
+ public ResourcesData resources { get; set; } = new ResourcesData();
+
+ /// <summary>
+ /// Gets a value that determines whether to enable caching of the <see cref="resources"/>
+ /// inside a CacheStorage instance within the browser.
+ /// </summary>
+ public bool cacheBootResources { get; set; }
+
+ /// <summary>
+ /// Gets a value that determines if this is a debug build.
+ /// </summary>
+ public bool debugBuild { get; set; }
+
+ /// <summary>
+ /// Gets a value that determines if the linker is enabled.
+ /// </summary>
+ public bool linkerEnabled { get; set; }
+
+ /// <summary>
+ /// Config files for the application
+ /// </summary>
+ public List<string> config { get; set; }
+ }
+
+ public class ResourcesData
+ {
+ /// <summary>
+ /// .NET Wasm runtime resources (dotnet.wasm, dotnet.js) etc.
+ /// </summary>
+ public ResourceHashesByNameDictionary runtime { get; set; } = new ResourceHashesByNameDictionary();
+
+ /// <summary>
+ /// "assembly" (.dll) resources
+ /// </summary>
+ public ResourceHashesByNameDictionary assembly { get; set; } = new ResourceHashesByNameDictionary();
+
+ /// <summary>
+ /// "debug" (.pdb) resources
+ /// </summary>
+ [DataMember(EmitDefaultValue = false)]
+ public ResourceHashesByNameDictionary pdb { get; set; }
+
+ /// <summary>
+ /// localization (.satellite resx) resources
+ /// </summary>
+ [DataMember(EmitDefaultValue = false)]
+ public Dictionary<string, ResourceHashesByNameDictionary> satelliteResources { get; set; }
+
+ /// <summary>
+ /// Assembly (.dll) resources that are loaded dynamically during runtime
+ /// </summary>
+ [DataMember(EmitDefaultValue = false)]
+ public ResourceHashesByNameDictionary dynamicAssembly { get; set; }
+ }
+#pragma warning restore IDE1006 // Naming Styles
+}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/BrotliCompress.cs b/src/Razor/Microsoft.NET.Sdk.Razor/src/BrotliCompress.cs
new file mode 100644
index 0000000000..9019f0520f
--- /dev/null
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/BrotliCompress.cs
@@ -0,0 +1,99 @@
+// 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.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Microsoft.AspNetCore.Razor.Tasks
+{
+ public class BrotliCompress : DotNetToolTask
+ {
+ private static readonly char[] InvalidPathChars = Path.GetInvalidFileNameChars();
+
+ [Required]
+ public ITaskItem[] FilesToCompress { get; set; }
+
+ [Output]
+ public ITaskItem[] CompressedFiles { get; set; }
+
+ [Required]
+ public string OutputDirectory { get; set; }
+
+ public string CompressionLevel { get; set; }
+
+ public bool SkipIfOutputIsNewer { get; set; }
+
+ internal override string Command => "brotli";
+
+ protected override string GenerateResponseFileCommands()
+ {
+ var builder = new StringBuilder();
+
+ builder.AppendLine(Command);
+
+ if (!string.IsNullOrEmpty(CompressionLevel))
+ {
+ builder.AppendLine("-c");
+ builder.AppendLine(CompressionLevel);
+ }
+
+ CompressedFiles = new ITaskItem[FilesToCompress.Length];
+
+ for (var i = 0; i < FilesToCompress.Length; i++)
+ {
+ var input = FilesToCompress[i];
+ var inputFullPath = input.GetMetadata("FullPath");
+ var relativePath = input.GetMetadata("RelativePath");
+ var outputRelativePath = Path.Combine(OutputDirectory, CalculateTargetPath(relativePath));
+
+ var outputItem = new TaskItem(outputRelativePath);
+ input.CopyMetadataTo(outputItem);
+ // Relative path in the publish dir
+ outputItem.SetMetadata("RelativePath", relativePath + ".br");
+ CompressedFiles[i] = outputItem;
+
+ var outputFullPath = Path.GetFullPath(outputRelativePath);
+
+ if (SkipIfOutputIsNewer && File.Exists(outputFullPath) && File.GetLastWriteTimeUtc(inputFullPath) < File.GetLastWriteTimeUtc(outputFullPath))
+ {
+ Log.LogMessage(MessageImportance.Low, $"Skipping compression for '{input.ItemSpec}' because '{outputRelativePath}' is newer than '{input.ItemSpec}'.");
+ continue;
+ }
+
+ builder.AppendLine("-s");
+ builder.AppendLine(inputFullPath);
+
+ builder.AppendLine("-o");
+ builder.AppendLine(outputFullPath);
+ }
+
+ return builder.ToString();
+ }
+
+ private static string CalculateTargetPath(string relativePath)
+ {
+ // RelativePath can be long and if used as-is to write the output, might result in long path issues on Windows.
+ // Instead we'll calculate a fixed length path by hashing the input file name. This uses SHA1 similar to the Hash task in MSBuild
+ // since it has no crytographic significance.
+ using var hash = SHA1.Create();
+ var bytes = Encoding.UTF8.GetBytes(relativePath);
+ var hashString = Convert.ToBase64String(hash.ComputeHash(bytes));
+
+ var builder = new StringBuilder();
+
+ for (var i = 0; i < 8; i++)
+ {
+ var c = hashString[i];
+ builder.Append(InvalidPathChars.Contains(c) ? '+' : c);
+ }
+
+ builder.Append(".br");
+ return builder.ToString();
+ }
+ }
+}
diff --git a/src/Components/WebAssembly/Build/src/Tasks/BlazorCreateRootDescriptorFile.cs b/src/Razor/Microsoft.NET.Sdk.Razor/src/CreateBlazorTrimmerRootDescriptorFile.cs
index 45359bdb8a..57fa43a979 100644
--- a/src/Components/WebAssembly/Build/src/Tasks/BlazorCreateRootDescriptorFile.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/CreateBlazorTrimmerRootDescriptorFile.cs
@@ -3,42 +3,53 @@
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
+namespace Microsoft.AspNetCore.Razor.Tasks
{
// Based on https://github.com/mono/linker/blob/3b329b9481e300bcf4fb88a2eebf8cb5ef8b323b/src/ILLink.Tasks/CreateRootDescriptorFile.cs
- public class BlazorCreateRootDescriptorFile : Task
+ public class CreateBlazorTrimmerRootDescriptorFile : Task
{
[Required]
- public ITaskItem[] AssemblyNames { get; set; }
+ public ITaskItem[] Assemblies { get; set; }
[Required]
- public ITaskItem RootDescriptorFilePath { get; set; }
+ public ITaskItem TrimmerFile { get; set; }
public override bool Execute()
{
- using var fileStream = File.Create(RootDescriptorFilePath.ItemSpec);
- var assemblyNames = AssemblyNames.Select(a => a.ItemSpec);
+ using var fileStream = File.Create(TrimmerFile.ItemSpec);
- WriteRootDescriptor(fileStream, assemblyNames);
+ WriteRootDescriptor(fileStream);
return true;
}
- internal static void WriteRootDescriptor(Stream stream, IEnumerable<string> assemblyNames)
+ internal void WriteRootDescriptor(Stream stream)
{
var roots = new XElement("linker");
- foreach (var assemblyName in assemblyNames)
+ foreach (var assembly in Assemblies)
{
+ var assemblyName = assembly.GetMetadata("FileName") + assembly.GetMetadata("Extension");
+ var typePreserved = assembly.GetMetadata("Preserve");
+ var typeRequired = assembly.GetMetadata("Required");
+
+ var attributes = new List<XAttribute>
+ {
+ new XAttribute("fullname", "*"),
+ new XAttribute("required", typeRequired),
+ };
+
+ if (!string.IsNullOrEmpty(typePreserved))
+ {
+ attributes.Add(new XAttribute("preserve", typePreserved));
+ }
+
roots.Add(new XElement("assembly",
new XAttribute("fullname", assemblyName),
- new XElement("type",
- new XAttribute("fullname", "*"),
- new XAttribute("required", "true"))));
+ new XElement("type", attributes)));
}
var xmlWriterSettings = new XmlWriterSettings
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/GenerateBlazorWebAssemblyBootJson.cs b/src/Razor/Microsoft.NET.Sdk.Razor/src/GenerateBlazorWebAssemblyBootJson.cs
new file mode 100644
index 0000000000..4d2c786443
--- /dev/null
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/GenerateBlazorWebAssemblyBootJson.cs
@@ -0,0 +1,155 @@
+// 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.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Serialization.Json;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary<string, string>;
+
+namespace Microsoft.AspNetCore.Razor.Tasks
+{
+ public class GenerateBlazorWebAssemblyBootJson : Task
+ {
+ [Required]
+ public string AssemblyPath { get; set; }
+
+ [Required]
+ public ITaskItem[] Resources { get; set; }
+
+ [Required]
+ public bool DebugBuild { get; set; }
+
+ [Required]
+ public bool LinkerEnabled { get; set; }
+
+ [Required]
+ public bool CacheBootResources { get; set; }
+
+ public ITaskItem[] ConfigurationFiles { get; set; }
+
+ [Required]
+ public string OutputPath { get; set; }
+
+ public ITaskItem[] LazyLoadedAssemblies { get; set; }
+
+ public override bool Execute()
+ {
+ using var fileStream = File.Create(OutputPath);
+ var entryAssemblyName = AssemblyName.GetAssemblyName(AssemblyPath).Name;
+
+ try
+ {
+ WriteBootJson(fileStream, entryAssemblyName);
+ }
+ catch (Exception ex)
+ {
+ Log.LogErrorFromException(ex);
+ }
+
+ return !Log.HasLoggedErrors;
+ }
+
+ // Internal for tests
+ public void WriteBootJson(Stream output, string entryAssemblyName)
+ {
+ var result = new BootJsonData
+ {
+ entryAssembly = entryAssemblyName,
+ cacheBootResources = CacheBootResources,
+ debugBuild = DebugBuild,
+ linkerEnabled = LinkerEnabled,
+ resources = new ResourcesData(),
+ config = new List<string>(),
+ };
+
+ // Build a two-level dictionary of the form:
+ // - assembly:
+ // - UriPath (e.g., "System.Text.Json.dll")
+ // - ContentHash (e.g., "4548fa2e9cf52986")
+ // - runtime:
+ // - UriPath (e.g., "dotnet.js")
+ // - ContentHash (e.g., "3448f339acf512448")
+ if (Resources != null)
+ {
+ var resourceData = result.resources;
+ foreach (var resource in Resources)
+ {
+ ResourceHashesByNameDictionary resourceList;
+
+ var fileName = resource.GetMetadata("FileName");
+ var extension = resource.GetMetadata("Extension");
+ var resourceCulture = resource.GetMetadata("Culture");
+ var assetType = resource.GetMetadata("AssetType");
+ var resourceName = $"{fileName}{extension}";
+
+ if (IsLazyLoadedAssembly(fileName))
+ {
+ resourceData.dynamicAssembly ??= new ResourceHashesByNameDictionary();
+ resourceList = resourceData.dynamicAssembly;
+ }
+ else if (!string.IsNullOrEmpty(resourceCulture))
+ {
+ resourceData.satelliteResources ??= new Dictionary<string, ResourceHashesByNameDictionary>(StringComparer.OrdinalIgnoreCase);
+ resourceName = resourceCulture + "/" + resourceName;
+
+ if (!resourceData.satelliteResources.TryGetValue(resourceCulture, out resourceList))
+ {
+ resourceList = new ResourceHashesByNameDictionary();
+ resourceData.satelliteResources.Add(resourceCulture, resourceList);
+ }
+ }
+ else if (string.Equals(extension, ".pdb", StringComparison.OrdinalIgnoreCase))
+ {
+ resourceData.pdb ??= new ResourceHashesByNameDictionary();
+ resourceList = resourceData.pdb;
+ }
+ else if (string.Equals(extension, ".dll", StringComparison.OrdinalIgnoreCase))
+ {
+ resourceList = resourceData.assembly;
+ }
+ else if (string.Equals(assetType, "native", StringComparison.OrdinalIgnoreCase))
+ {
+ resourceList = resourceData.runtime;
+ }
+ else
+ {
+ // This should include items such as XML doc files, which do not need to be recorded in the manifest.
+ continue;
+ }
+
+ if (!resourceList.ContainsKey(resourceName))
+ {
+ resourceList.Add(resourceName, $"sha256-{resource.GetMetadata("FileHash")}");
+ }
+ }
+ }
+
+ if (ConfigurationFiles != null)
+ {
+ foreach (var configFile in ConfigurationFiles)
+ {
+ result.config.Add(Path.GetFileName(configFile.ItemSpec));
+ }
+ }
+
+ var serializer = new DataContractJsonSerializer(typeof(BootJsonData), new DataContractJsonSerializerSettings
+ {
+ UseSimpleDictionaryFormat = true
+ });
+
+ using var writer = JsonReaderWriterFactory.CreateJsonWriter(output, Encoding.UTF8, ownsStream: false, indent: true);
+ serializer.WriteObject(writer, result);
+ }
+
+ private bool IsLazyLoadedAssembly(string fileName)
+ {
+ return LazyLoadedAssemblies != null && LazyLoadedAssemblies.Any(a => a.ItemSpec == fileName);
+ }
+ }
+}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/GenerateServiceWorkerAssetsManifest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/src/GenerateServiceWorkerAssetsManifest.cs
new file mode 100644
index 0000000000..8e5f0d39e7
--- /dev/null
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/GenerateServiceWorkerAssetsManifest.cs
@@ -0,0 +1,97 @@
+// 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.IO;
+using System.Linq;
+using System.Runtime.Serialization.Json;
+using System.Security.Cryptography;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Microsoft.AspNetCore.Razor.Tasks
+{
+ public partial class GenerateServiceWorkerAssetsManifest : Task
+ {
+ [Required]
+ public ITaskItem[] Assets { get; set; }
+
+ public string Version { get; set; }
+
+ [Required]
+ public string OutputPath { get; set; }
+
+ [Output]
+ public string CalculatedVersion { get; set; }
+
+ public override bool Execute()
+ {
+ using var fileStream = File.Create(OutputPath);
+ CalculatedVersion = GenerateAssetManifest(fileStream);
+
+ return true;
+ }
+
+ internal string GenerateAssetManifest(Stream stream)
+ {
+ var assets = new AssetsManifestFileEntry[Assets.Length];
+ System.Threading.Tasks.Parallel.For(0, assets.Length, i =>
+ {
+ var item = Assets[i];
+ var hash = item.GetMetadata("FileHash");
+ var url = item.GetMetadata("AssetUrl");
+
+ if (string.IsNullOrEmpty(hash))
+ {
+ // Some files that are part of the service worker manifest may not have their hashes previously
+ // calcualted. Calculate them at this time.
+ using var sha = SHA256.Create();
+ using var file = File.OpenRead(item.ItemSpec);
+ var bytes = sha.ComputeHash(file);
+
+ hash = Convert.ToBase64String(bytes);
+ }
+
+ assets[i] = new AssetsManifestFileEntry
+ {
+ hash = "sha256-" + hash,
+ url = url,
+ };
+ });
+
+ var version = Version;
+ if (string.IsNullOrEmpty(version))
+ {
+ // If a version isn't specified (which is likely the most common case), construct a Version by combining
+ // the file names + hashes of all the inputs.
+
+ var combinedHash = string.Join(
+ Environment.NewLine,
+ assets.OrderBy(f => f.url, StringComparer.Ordinal).Select(f => f.hash));
+
+ using var sha = SHA256.Create();
+ var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(combinedHash));
+ version = Convert.ToBase64String(bytes).Substring(0, 8);
+ }
+
+ var data = new AssetsManifestFile
+ {
+ version = version,
+ assets = assets,
+ };
+
+ using var streamWriter = new StreamWriter(stream, Encoding.UTF8, bufferSize: 50, leaveOpen: true);
+ streamWriter.Write("self.assetsManifest = ");
+ streamWriter.Flush();
+
+ using var jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, ownsStream: false, indent: true);
+ new DataContractJsonSerializer(typeof(AssetsManifestFile)).WriteObject(jsonWriter, data);
+ jsonWriter.Flush();
+
+ streamWriter.WriteLine(";");
+
+ return version;
+ }
+ }
+}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/Microsoft.NET.Sdk.Razor.csproj b/src/Razor/Microsoft.NET.Sdk.Razor/src/Microsoft.NET.Sdk.Razor.csproj
index efe499aaca..42cb964335 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/src/Microsoft.NET.Sdk.Razor.csproj
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/Microsoft.NET.Sdk.Razor.csproj
@@ -34,12 +34,10 @@
<ProjectReference
Include="..\..\Microsoft.AspNetCore.Mvc.Razor.Extensions\src\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj"
- Targets="Publish"
ReferenceOutputAssembly="false"
IsImplicityDefined="false"
SkipGetTargetFrameworkProperties="true"
UndefineProperties="TargetFramework;TargetFrameworks" />
-
</ItemGroup>
<ItemGroup>
diff --git a/src/Components/WebAssembly/Build/src/targets/Standalone.Web.config b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/BlazorWasm.web.config
index 7f9995d792..7f9995d792 100644
--- a/src/Components/WebAssembly/Build/src/targets/Standalone.Web.config
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/BlazorWasm.web.config
diff --git a/src/Components/WebAssembly/Build/src/targets/BuiltInBclLinkerDescriptor.xml b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/LinkerWorkaround.xml
index 6fb65f5a14..4461d2fc12 100644
--- a/src/Components/WebAssembly/Build/src/targets/BuiltInBclLinkerDescriptor.xml
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/LinkerWorkaround.xml
@@ -4,12 +4,6 @@
by the IL linker even if they are not referenced by user code. The file format is
described at https://github.com/mono/linker/blob/master/src/linker/README.md#syntax-of-xml-descriptor -->
- <assembly fullname="mscorlib">
- <!-- Preserve all methods on WasmRuntime, because these are called by JS-side code
- to implement timers. Fixes https://github.com/dotnet/blazor/issues/239 -->
- <type fullname="System.Threading.WasmRuntime" />
- </assembly>
-
<assembly fullname="System">
<!-- Without this, [Required(typeof(bool), "true", "true", ErrorMessage = "...")] fails -->
<type fullname="System.ComponentModel.BooleanConverter" />
@@ -19,6 +13,8 @@
<type fullname="System.ComponentModel.TimeSpanConverter" />
</assembly>
+ <assembly fullname="System.Runtime.InteropServices.JavaScript" preserve="all" />
+
<assembly fullname="System.Text.Json">
<!-- S.T.J. uses Activator.CreateInstance to instantiate converters, so we need to preserve default constructors.
For safety, do this for all converter types, even though most of them are preserved anyway due to being referenced
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.CodeGeneration.targets b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.CodeGeneration.targets
index 5f8081d69c..99a7c037b8 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.CodeGeneration.targets
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.CodeGeneration.targets
@@ -38,8 +38,6 @@ Copyright (c) .NET Foundation. All rights reserved.
<!-- Used to hash file inputs for RazorGenerate -->
<_RazorGenerateInputsHash></_RazorGenerateInputsHash>
<_RazorGenerateInputsHashFile>$(IntermediateOutputPath)$(MSBuildProjectName).RazorCoreGenerate.cache</_RazorGenerateInputsHashFile>
-
- <_RazorToolAssembly Condition="'$(_RazorToolAssembly)'==''">$(RazorSdkDirectoryRoot)tools\netcoreapp3.0\rzc.dll</_RazorToolAssembly>
</PropertyGroup>
<!--
@@ -99,7 +97,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<RazorTagHelper
Debug="$(_RazorDebugTagHelperTask)"
DebugTool="$(_RazorDebugTagHelperTool)"
- ToolAssembly="$(_RazorToolAssembly)"
+ ToolAssembly="$(_RazorSdkToolAssembly)"
UseServer="$(UseRazorBuildServer)"
ForceServer="$(_RazorForceBuildServer)"
PipeName="$(_RazorBuildServerPipeName)"
@@ -150,7 +148,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<RazorGenerate
Debug="$(_RazorDebugGenerateCodeTask)"
DebugTool="$(_RazorDebugGenerateCodeTool)"
- ToolAssembly="$(_RazorToolAssembly)"
+ ToolAssembly="$(_RazorSdkToolAssembly)"
UseServer="$(UseRazorBuildServer)"
ForceServer="$(_RazorForceBuildServer)"
PipeName="$(_RazorBuildServerPipeName)"
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Component.targets b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Component.targets
index b208426546..89e93a3a98 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Component.targets
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Component.targets
@@ -106,7 +106,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<RazorGenerate
Debug="$(_RazorDebugGenerateCodeTask)"
DebugTool="$(_RazorDebugGenerateCodeTool)"
- ToolAssembly="$(_RazorToolAssembly)"
+ ToolAssembly="$(_RazorSdkToolAssembly)"
UseServer="$(UseRazorBuildServer)"
ForceServer="$(_RazorForceBuildServer)"
PipeName="$(_RazorBuildServerPipeName)"
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Components.ServiceWorkerAssetsManifest.targets b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Components.ServiceWorkerAssetsManifest.targets
new file mode 100644
index 0000000000..8fdef1b4b3
--- /dev/null
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Components.ServiceWorkerAssetsManifest.targets
@@ -0,0 +1,166 @@
+<!--
+***********************************************************************************************
+Microsoft.NET.Sdk.Razor.Components.ServiceWorkerAssetsManifest.targets
+
+WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
+ created a backup copy. Incorrect changes to this file will make it
+ impossible to load or build your projects from the command-line or the IDE.
+
+Copyright (c) .NET Foundation. All rights reserved.
+***********************************************************************************************
+-->
+
+<Project>
+ <UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.GenerateServiceWorkerAssetsManifest" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
+
+ <Target Name="_ComputeServiceWorkerAssets" BeforeTargets="ResolveStaticWebAssetsInputs">
+ <PropertyGroup>
+ <_ServiceWorkerAssetsManifestIntermediateOutputPath>$(IntermediateOutputPath)$(ServiceWorkerAssetsManifest)</_ServiceWorkerAssetsManifestIntermediateOutputPath>
+ <_ServiceWorkerAssetsManifestFullPath>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)/$(_ServiceWorkerAssetsManifestIntermediateOutputPath)'))</_ServiceWorkerAssetsManifestFullPath>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <_ManifestStaticWebAsset Include="$(_ServiceWorkerAssetsManifestFullPath)">
+ <SourceType></SourceType>
+ <SourceId>$(PackageId)</SourceId>
+ <ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
+ <BasePath>$(StaticWebAssetBasePath)</BasePath>
+ <RelativePath>$(ServiceWorkerAssetsManifest)</RelativePath>
+ <CopyToPublishDirectory>Never</CopyToPublishDirectory>
+ </_ManifestStaticWebAsset>
+
+ <!-- Figure out where we're getting the content for each @(ServiceWorker) entry, depending on whether there's a PublishedContent value -->
+ <_ServiceWorkerIntermediateFile Include="@(ServiceWorker->'$(IntermediateOutputPath)serviceworkers\%(Identity)')">
+ <ContentSourcePath Condition="'%(_ServiceWorker.PublishedContent)' != ''">%(ServiceWorker.PublishedContent)</ContentSourcePath>
+ <ContentSourcePath Condition="'%(_ServiceWorker.PublishedContent)' == ''">%(ServiceWorker.Identity)</ContentSourcePath>
+ <OriginalPath>%(ServiceWorker.Identity)</OriginalPath>
+ <TargetOutputPath>%(ServiceWorker.Identity)</TargetOutputPath>
+ <TargetOutputPath Condition="$([System.String]::Copy('%(ServiceWorker.Identity)').Replace('\','/').StartsWith('wwwroot/'))">$([System.String]::Copy('%(ServiceWorker.Identity)').Substring(8))</TargetOutputPath>
+ </_ServiceWorkerIntermediateFile>
+
+ <_ServiceWorkerStaticWebAsset Include="%(_ServiceWorkerIntermediateFile.FullPath)">
+ <SourceType></SourceType>
+ <SourceId>$(PackageId)</SourceId>
+ <ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
+ <BasePath>$(StaticWebAssetBasePath)</BasePath>
+ <RelativePath>%(TargetOutputPath)</RelativePath>
+ <CopyToPublishDirectory>Never</CopyToPublishDirectory>
+ </_ServiceWorkerStaticWebAsset>
+
+ <StaticWebAsset Include="
+ @(_ManifestStaticWebAsset);
+ @(_ServiceWorkerStaticWebAsset)" />
+ </ItemGroup>
+
+ </Target>
+
+ <Target Name="_WriteServiceWorkerAssetsManifest"
+ DependsOnTargets="_ComputeServiceWorkerAssets;ResolveStaticWebAssetsInputs">
+
+ <ItemGroup>
+ <_ServiceWorkItem Include="@(StaticWebAsset)" Exclude="$(_ServiceWorkerAssetsManifestFullPath);@(_ServiceWorkerStaticWebAsset)">
+ <AssetUrl>$([System.String]::Copy('$([System.String]::Copy('%(StaticWebAsset.BasePath)').TrimEnd('/'))/%(StaticWebAsset.RelativePath)').Replace('\','/').TrimStart('/'))</AssetUrl>
+ </_ServiceWorkItem>
+ </ItemGroup>
+
+ <GenerateServiceWorkerAssetsManifest
+ Version="$(ServiceWorkerAssetsManifestVersion)"
+ Assets="@(_ServiceWorkItem)"
+ OutputPath="$(_ServiceWorkerAssetsManifestIntermediateOutputPath)">
+ <Output TaskParameter="CalculatedVersion" PropertyName="_ServiceWorkerAssetsManifestVersion" />
+ </GenerateServiceWorkerAssetsManifest>
+
+ <Copy
+ SourceFiles="%(_ServiceWorkerIntermediateFile.ContentSourcePath)"
+ DestinationFiles="%(_ServiceWorkerIntermediateFile.Identity)" />
+
+ <WriteLinesToFile
+ File="%(_ServiceWorkerIntermediateFile.Identity)"
+ Lines="/* Manifest version: $(_ServiceWorkerAssetsManifestVersion) */"
+ Condition="'$(_ServiceWorkerAssetsManifestVersion)' != ''" />
+
+ <ItemGroup>
+ <FileWrites Include="@(_ServiceWorkerIntermediateFile)" />
+ <FileWrites Include="$(_ServiceWorkerAssetsManifestIntermediateOutputPath)" />
+ </ItemGroup>
+
+ </Target>
+
+ <Target Name="_BlazorStaticAssetsCopyFilesToOutputDirectory" AfterTargets="CopyFilesToOutputDirectory" DependsOnTargets="_WriteServiceWorkerAssetsManifest">
+ <Copy
+ SourceFiles="@(_ManifestStaticWebAsset);@(_ServiceWorkerStaticWebAsset)"
+ DestinationFiles="$(OutDir)wwwroot\%(RelativePath)"
+ SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
+ OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
+ Retries="$(CopyRetryCount)"
+ RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
+ UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
+ UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
+ ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)">
+
+ <Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
+ </Copy>
+ </Target>
+
+ <Target Name="_OmitServiceWorkerContent"
+ BeforeTargets="AssignTargetPaths;ResolveCurrentProjectStaticWebAssetsInputs">
+
+ <ItemGroup>
+ <!-- Don't emit the service worker source files to the output -->
+ <Content Remove="@(ServiceWorker)" />
+ <Content Remove="@(ServiceWorker->'%(PublishedContent)')" />
+ </ItemGroup>
+ </Target>
+
+ <Target Name="_GenerateServiceWorkerFileForPublish"
+ BeforeTargets="_BlazorCompressPublishFiles"
+ AfterTargets="_ProcessPublishFilesForBlazor">
+
+ <PropertyGroup>
+ <_ServiceWorkerAssetsManifestPublishIntermediateOutputPath>$(IntermediateOutputPath)publish-$(ServiceWorkerAssetsManifest)</_ServiceWorkerAssetsManifestPublishIntermediateOutputPath>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <_ServiceWorkerIntermediatePublishFile Include="%(ServiceWorker.IntermediateOutputPath)serviceworkers\%(FileName).publish%(Extension)">
+ <ContentSourcePath Condition="'%(ServiceWorker.PublishedContent)' != ''">%(ServiceWorker.PublishedContent)</ContentSourcePath>
+ <ContentSourcePath Condition="'%(ServiceWorker.PublishedContent)' == ''">%(ServiceWorker.Identity)</ContentSourcePath>
+ <RelativePath>%(ServiceWorker.Identity)</RelativePath>
+ </_ServiceWorkerIntermediatePublishFile>
+
+ <_ServiceWorkerPublishFile Include="@(ResolvedFileToPublish)" Condition="$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))">
+ <AssetUrl>$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').TrimStart('/'))</AssetUrl>
+ <AssetUrl>$([System.String]::Copy('%(RelativePath)').Replace('\','/').Substring(8))</AssetUrl>
+ </_ServiceWorkerPublishFile>
+ </ItemGroup>
+
+ <GenerateServiceWorkerAssetsManifest
+ Version="$(ServiceWorkerAssetsManifestVersion)"
+ Assets="@(_ServiceWorkerPublishFile)"
+ OutputPath="$(_ServiceWorkerAssetsManifestPublishIntermediateOutputPath)">
+
+ <Output TaskParameter="CalculatedVersion" PropertyName="_ServiceWorkerPublishAssetsManifestVersion" />
+ </GenerateServiceWorkerAssetsManifest>
+
+ <Copy SourceFiles="%(_ServiceWorkerIntermediatePublishFile.ContentSourcePath)"
+ DestinationFiles="%(_ServiceWorkerIntermediatePublishFile.Identity)" />
+
+ <WriteLinesToFile
+ File="%(_ServiceWorkerIntermediatePublishFile.Identity)"
+ Lines="/* Manifest version: $(_ServiceWorkerPublishAssetsManifestVersion) */" />
+
+ <ItemGroup>
+ <ResolvedFileToPublish
+ Include="@(_ServiceWorkerIntermediatePublishFile)"
+ CopyToPublishDirectory="PreserveNewest"
+ RelativePath="%(_ServiceWorkerIntermediatePublishFile.RelativePath)"
+ ExcludeFromSingleFile="true" />
+
+ <ResolvedFileToPublish
+ Include="$(_ServiceWorkerAssetsManifestPublishIntermediateOutputPath)"
+ CopyToPublishDirectory="PreserveNewest"
+ RelativePath="wwwroot\$(ServiceWorkerAssetsManifest)"
+ ExcludeFromSingleFile="true" />
+ </ItemGroup>
+ </Target>
+
+</Project>
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Components.Wasm.targets b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Components.Wasm.targets
new file mode 100644
index 0000000000..fe977ecdc0
--- /dev/null
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Components.Wasm.targets
@@ -0,0 +1,490 @@
+<!--
+***********************************************************************************************
+Microsoft.NET.Sdk.Razor.Components.Wasm.targets
+
+WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
+ created a backup copy. Incorrect changes to this file will make it
+ impossible to load or build your projects from the command-line or the IDE.
+
+Copyright (c) .NET Foundation. All rights reserved.
+***********************************************************************************************
+-->
+
+<Project ToolsVersion="14.0">
+ <UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.GenerateBlazorWebAssemblyBootJson" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
+ <UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.BlazorWriteSatelliteAssemblyFile" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
+ <UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.BlazorReadSatelliteAssemblyFile" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
+ <UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.BrotliCompress" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
+ <UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.CreateBlazorTrimmerRootDescriptorFile" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
+
+ <PropertyGroup>
+ <PublishTrimmed Condition="'$(PublishTrimmed)' == ''">true</PublishTrimmed>
+ <SelfContained>true</SelfContained>
+ <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
+
+ <StaticWebAssetBasePath Condition="'$(StaticWebAssetBasePath)' == ''">/</StaticWebAssetBasePath>
+ <BlazorCacheBootResources Condition="'$(BlazorCacheBootResources)' == ''">true</BlazorCacheBootResources>
+
+ <!-- Turn off parts of the build that do not apply to WASM projects -->
+ <GenerateDependencyFile>false</GenerateDependencyFile>
+ <GenerateRuntimeConfigurationFiles>false</GenerateRuntimeConfigurationFiles>
+ <PreserveCompilationContext>false</PreserveCompilationContext>
+ <PreserveCompilationReferences>false</PreserveCompilationReferences>
+ <AddRazorSupportForMvc>false</AddRazorSupportForMvc>
+ <OutputType>exe</OutputType>
+
+ <!-- Internal properties -->
+ <_BlazorOutputPath>wwwroot\_framework\</_BlazorOutputPath>
+ <_BlazorSatelliteAssemblyCacheFile>$(IntermediateOutputPath)blazor.satelliteasm.props</_BlazorSatelliteAssemblyCacheFile>
+
+ <!-- Workaround for https://github.com/dotnet/sdk/issues/12114-->
+ <PublishDir Condition="'$(AppendRuntimeIdentifierToOutputPath)' != 'true' AND '$(PublishDir)' == '$(OutputPath)$(RuntimeIdentifier)\$(PublishDirName)\'">$(OutputPath)$(PublishDirName)\</PublishDir>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <FrameworkReference Remove="Microsoft.AspNetCore.App" />
+ <KnownFrameworkReference Remove="Microsoft.AspNetCore.App" />
+ </ItemGroup>
+
+ <!-- Temporary workaround until ILLink.targets are updated -->
+ <PropertyGroup Condition=" '$(PublishTrimmed)' == 'true' ">
+ <IntermediateLinkDir Condition=" '$(IntermediateLinkDir)' == '' ">$(IntermediateOutputPath)linked\</IntermediateLinkDir>
+ <IntermediateLinkDir Condition=" !HasTrailingSlash('$(IntermediateLinkDir)') ">$(IntermediateLinkDir)\</IntermediateLinkDir>
+ <!-- Used to enable incremental build for the linker target. -->
+ <_LinkSemaphore>$(IntermediateOutputPath)Link.semaphore</_LinkSemaphore>
+ </PropertyGroup>
+
+ <Import Project="Microsoft.NET.Sdk.Razor.Components.ServiceWorkerAssetsManifest.targets" Condition="'$(ServiceWorkerAssetsManifest)' != ''" />
+
+ <Target Name="_ScrambleDotnetJsFileName" AfterTargets="ResolveRuntimePackAssets">
+ <!--
+ We want the dotnet.js file output to have a version to better work with caching. We'll append the runtime version to the file name as soon as file has been discovered.
+ -->
+ <PropertyGroup>
+ <_DotNetJsVersion>$(BundledNETCoreAppPackageVersion)</_DotNetJsVersion>
+ <_DotNetJsVersion Condition="'$(RuntimeFrameworkVersion)' != ''">$(RuntimeFrameworkVersion)</_DotNetJsVersion>
+ <_BlazorDotnetJsFileName>dotnet.$(_DotNetJsVersion).js</_BlazorDotnetJsFileName>
+ <_BlazorDotNetJsFilePath>$(IntermediateOutputPath)$(_BlazorDotnetJsFileName)</_BlazorDotNetJsFilePath>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <_DotNetJsItem Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.DestinationSubPath)' == 'dotnet.js' AND '%(ReferenceCopyLocalPaths.AssetType)' == 'native'" />
+ </ItemGroup>
+
+ <Copy
+ SourceFiles="@(_DotNetJsItem)"
+ DestinationFiles="$(_BlazorDotNetJsFilePath)"
+ SkipUnchangedFiles="true"
+ OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)" />
+
+ <ItemGroup Condition="'@(_DotNetJsItem->Count())' != '0'">
+ <ReferenceCopyLocalPaths
+ Include="$(_BlazorDotNetJsFilePath)"
+ AssetType="native"
+ CopyLocal="true"
+ DestinationSubPath="$(_BlazorDotnetJsFileName)" />
+
+ <ReferenceCopyLocalPaths Remove="@(_DotNetJsItem)" />
+ </ItemGroup>
+ </Target>
+
+ <Target Name="_ResolveBlazorWasmOutputs" DependsOnTargets="ResolveReferences;PrepareResourceNames;ComputeIntermediateSatelliteAssemblies">
+ <!--
+ Calculates the outputs and the paths for Blazor WASM. This target is invoked frequently and should perform minimal work.
+ -->
+ <ItemGroup>
+ <_BlazorJSFile Include="$(BlazorWebAssemblyJSPath)" />
+ <_BlazorJSFile Include="$(BlazorWebAssemblyJSMapPath)" Condition="Exists('$(BlazorWebAssemblyJSMapPath)')" />
+
+ <_BlazorConfigFile Include="wwwroot\appsettings*.json" />
+
+ <!-- Clear out temporary build artifacts that the runtime packages -->
+ <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.a'" />
+
+ <!--
+ ReferenceCopyLocalPaths includes satellite assemblies from referenced projects but are inexpicably missing
+ any metadata that might allow them to be differentiated. We'll explicitly add those
+ to _BlazorOutputWithTargetPath so that satellite assemblies from packages, the current project and referenced project
+ are all treated the same.
+ -->
+
+ <_BlazorCopyLocalPath
+ Include="@(ReferenceCopyLocalPaths)"
+ Exclude="@(ReferenceSatellitePaths)"/>
+
+ <_BlazorCopyLocalPath Include="@(IntermediateSatelliteAssembliesWithTargetPath)">
+ <DestinationSubDirectory>%(IntermediateSatelliteAssembliesWithTargetPath.Culture)\</DestinationSubDirectory>
+ </_BlazorCopyLocalPath>
+
+ <_BlazorOutputWithTargetPath Include="
+ @(_BlazorCopyLocalPath);
+ @(IntermediateAssembly);
+ @(_DebugSymbolsIntermediatePath);
+ @(_BlazorJSFile)" />
+
+ <_BlazorOutputWithTargetPath Include="@(ReferenceSatellitePaths)">
+ <Culture>$([System.String]::Copy('%(ReferenceSatellitePaths.DestinationSubDirectory)').Trim('\').Trim('/'))</Culture>
+ </_BlazorOutputWithTargetPath>
+ </ItemGroup>
+
+ <!--
+ BuildingProject=false is typically set for referenced projects when building inside VisualStudio.
+
+ When building with BuildingProject=false, satellite assemblies do not get resolved (the ones for the current project and the one for
+ referenced project). Satellite assemblies from packages get resolved.
+ To workaround this, we'll cache metadata during a regular build, and rehydrate from it when BuildingProject=false.
+ -->
+ <BlazorReadSatelliteAssemblyFile
+ ReadFile="$(_BlazorSatelliteAssemblyCacheFile)"
+ Condition="'$(BuildingProject)' != 'true' AND EXISTS('$(_BlazorSatelliteAssemblyCacheFile)')">
+ <Output TaskParameter="SatelliteAssembly" ItemName="_BlazorReadSatelliteAssembly" />
+ </BlazorReadSatelliteAssemblyFile>
+
+ <ItemGroup >
+ <!-- We've imported a previously Cacheed file. Let's turn in to a _BlazorOutputWithTargetPath -->
+ <_BlazorOutputWithTargetPath
+ Include="@(_BlazorReadSatelliteAssembly)"
+ Exclude="@(_BlazorOutputWithTargetPath)"
+ Condition="'@(_BlazorReadSatelliteAssembly->Count())' != '0'" />
+
+ <!-- Calculate the target path -->
+ <_BlazorOutputWithTargetPath
+ TargetPath="$(_BlazorOutputPath)%(_BlazorOutputWithTargetPath.DestinationSubDirectory)%(FileName)%(Extension)"
+ Condition="'%(__BlazorOutputWithTargetPath.TargetPath)' == ''" />
+ </ItemGroup>
+ </Target>
+
+ <Target Name="_ProcessBlazorWasmOutputs" DependsOnTargets="_ResolveBlazorWasmOutputs">
+ <ItemGroup>
+ <_BlazorWriteSatelliteAssembly Include="@(_BlazorOutputWithTargetPath->HasMetadata('Culture'))" />
+
+ <!-- Retarget ReferenceCopyLocalPaths to copy to the wwwroot directory -->
+ <ReferenceCopyLocalPaths DestinationSubDirectory="$(_BlazorOutputPath)%(ReferenceCopyLocalPaths.DestinationSubDirectory)" />
+ </ItemGroup>
+
+ <!--
+ When building with BuildingProject=false, satellite assemblies do not get resolved (the ones for the current project and the one for
+ referenced project). BuildingProject=false is typically set for referenced projects when building inside VisualStudio.
+ To workaround this, we'll cache metadata during a regular build, and rehydrate from it when BuildingProject=false.
+ -->
+
+ <BlazorWriteSatelliteAssemblyFile
+ SatelliteAssembly="@(_BlazorWriteSatelliteAssembly)"
+ WriteFile="$(_BlazorSatelliteAssemblyCacheFile)"
+ Condition="'$(BuildingProject)' == 'true' AND '@(_BlazorWriteSatelliteAssembly->Count())' != '0'" />
+
+ <Delete
+ Files="$(_BlazorSatelliteAssemblyCacheFile)"
+ Condition="'$(BuildingProject)' == 'true' AND '@(_BlazorWriteSatelliteAssembly->Count())' == '0' and EXISTS('$(_BlazorSatelliteAssemblyCacheFile)')" />
+
+ <ItemGroup>
+ <FileWrites Include="$(_BlazorSatelliteAssemblyCacheFile)" Condition="Exists('$(_BlazorSatelliteAssemblyCacheFile)')" />
+ </ItemGroup>
+
+ <GetFileHash Files="@(_BlazorOutputWithTargetPath)" Algorithm="SHA256" HashEncoding="base64">
+ <Output TaskParameter="Items" ItemName="_BlazorOutputWithHash" />
+ </GetFileHash>
+ </Target>
+
+ <PropertyGroup>
+ <PrepareForRunDependsOn>
+ _BlazorWasmPrepareForRun;
+ $(PrepareForRunDependsOn)
+ </PrepareForRunDependsOn>
+
+ <GetCurrentProjectStaticWebAssetsDependsOn>
+ $(GetCurrentProjectStaticWebAssetsDependsOn);
+ _BlazorWasmPrepareForRun;
+ </GetCurrentProjectStaticWebAssetsDependsOn>
+ </PropertyGroup>
+
+ <Target Name="_BlazorWasmPrepareForRun" DependsOnTargets="_ProcessBlazorWasmOutputs">
+ <PropertyGroup>
+ <_BlazorBuildBootJsonPath>$(IntermediateOutputPath)blazor.boot.json</_BlazorBuildBootJsonPath>
+ </PropertyGroup>
+
+ <GenerateBlazorWebAssemblyBootJson
+ AssemblyPath="@(IntermediateAssembly)"
+ Resources="@(_BlazorOutputWithHash)"
+ DebugBuild="true"
+ LinkerEnabled="false"
+ CacheBootResources="$(BlazorCacheBootResources)"
+ OutputPath="$(_BlazorBuildBootJsonPath)"
+ ConfigurationFiles="@(_BlazorConfigFile)"
+ LazyLoadedAssemblies="@(BlazorWebAssemblyLazyLoad)" />
+
+ <ItemGroup>
+ <FileWrites Include="$(OutDir)$(_BlazorOutputPath)blazor.boot.json" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <_BlazorWebAssemblyStaticWebAsset Include="$(_BlazorBuildBootJsonPath)">
+ <SourceId>$(PackageId)</SourceId>
+ <SourceType></SourceType>
+ <ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
+ <BasePath>$(StaticWebAssetBasePath)</BasePath>
+ <RelativePath>_framework/blazor.boot.json</RelativePath>
+ <CopyToPublishDirectory>Never</CopyToPublishDirectory>
+ </_BlazorWebAssemblyStaticWebAsset>
+
+ <_BlazorWebAssemblyStaticWebAsset Include="@(_BlazorOutputWithHash)">
+ <SourceId>$(PackageId)</SourceId>
+ <SourceType></SourceType>
+ <ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
+ <BasePath>$(StaticWebAssetBasePath)</BasePath>
+ <RelativePath>$([System.String]::Copy('%(_BlazorOutputWithHash.TargetPath)').Replace('\','/').Substring(8))</RelativePath>
+ <CopyToPublishDirectory>Never</CopyToPublishDirectory>
+ </_BlazorWebAssemblyStaticWebAsset>
+
+ <StaticWebAsset Include="@(_BlazorWebAssemblyStaticWebAsset)" />
+ <_ExternalStaticWebAsset Include="@(_BlazorWebAssemblyStaticWebAsset)" SourceType="Generated" />
+ </ItemGroup>
+ </Target>
+
+ <!-- Mimics the behavior of CopyFilesToOutputDirectory. We simply copy relevant build outputs to the wwwroot directory -->
+ <Target Name="_BlazorCopyFilesToOutputDirectory" AfterTargets="CopyFilesToOutputDirectory">
+ <Copy
+ SourceFiles="@(IntermediateAssembly)"
+ DestinationFolder="$(OutDir)$(_BlazorOutputPath)"
+ SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
+ OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
+ Retries="$(CopyRetryCount)"
+ RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
+ UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
+ UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
+ ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)"
+ Condition="'$(CopyBuildOutputToOutputDirectory)' == 'true' and '$(SkipCopyBuildProduct)' != 'true'">
+
+ <Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
+ </Copy>
+
+ <Message Importance="High" Text="$(MSBuildProjectName) (Blazor output) -&gt; $(TargetDir)wwwroot" Condition="'$(CopyBuildOutputToOutputDirectory)' == 'true' and '$(SkipCopyBuildProduct)'!='true'" />
+
+ <Copy
+ SourceFiles="@(_DebugSymbolsIntermediatePath)"
+ DestinationFolder="$(OutDir)$(_BlazorOutputPath)"
+ SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
+ OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
+ Retries="$(CopyRetryCount)"
+ RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
+ UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
+ UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
+ ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)"
+ Condition="'$(_DebugSymbolsProduced)'=='true' and '$(SkipCopyingSymbolsToOutputDirectory)' != 'true' and '$(CopyOutputSymbolsToOutputDirectory)'=='true'">
+
+ <Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
+ </Copy>
+
+ <Copy
+ SourceFiles="@(IntermediateSatelliteAssembliesWithTargetPath)"
+ DestinationFiles="@(IntermediateSatelliteAssembliesWithTargetPath->'$(OutDir)$(_BlazorOutputPath)%(Culture)\$(TargetName).resources.dll')"
+ SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
+ OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
+ Retries="$(CopyRetryCount)"
+ RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
+ UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
+ UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
+ ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)"
+ Condition="'@(IntermediateSatelliteAssembliesWithTargetPath)' != ''" >
+
+ <Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
+ </Copy>
+
+ <Copy
+ SourceFiles="@(_BlazorJSFile);$(_BlazorBuildBootJsonPath)"
+ DestinationFolder="$(OutDir)$(_BlazorOutputPath)"
+ SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
+ OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
+ Retries="$(CopyRetryCount)"
+ RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
+ UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
+ UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
+ ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)">
+
+ <Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
+ </Copy>
+ </Target>
+
+ <Target Name="_CreateBlazorTrimmerRootDescriptorFiles" BeforeTargets="ILLink" AfterTargets="ComputeResolvedFilesToPublishList">
+ <PropertyGroup>
+ <_BlazorApplicationTrimmerDescriptorFile>$(IntermediateOutputPath)default.trimmerdescriptor.xml</_BlazorApplicationTrimmerDescriptorFile>
+ <_BlazorTypeGranularTrimmerDescriptorFile>$(IntermediateOutputPath)typegranularity.trimmerdescriptor.xml</_BlazorTypeGranularTrimmerDescriptorFile>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <_BlazorTypeGranularAssembly
+ Include="@(ResolvedFileToPublish)"
+ Condition="$([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.')) or $([System.String]::Copy('%(Filename)').StartsWith('Microsoft.Extensions.'))">
+ <Required>false</Required>
+ <Preserve>all</Preserve>
+ </_BlazorTypeGranularAssembly>
+
+ <_BlazorApplicationAssembly Include="@(IntermediateAssembly)">
+ <Required>true</Required>
+ </_BlazorApplicationAssembly>
+ </ItemGroup>
+
+ <CreateBlazorTrimmerRootDescriptorFile
+ Assemblies="@(_BlazorApplicationAssembly)"
+ TrimmerFile="$(_BlazorApplicationTrimmerDescriptorFile)" />
+
+ <CreateBlazorTrimmerRootDescriptorFile
+ Assemblies="@(_BlazorTypeGranularAssembly)"
+ TrimmerFile="$(_BlazorTypeGranularTrimmerDescriptorFile)" />
+
+ <ItemGroup>
+ <TrimmerRootDescriptor Include="$(_BlazorApplicationTrimmerDescriptorFile)" />
+ <TrimmerRootDescriptor Include="$(MSBuildThisFileDirectory)LinkerWorkaround.xml" />
+
+ <FileWrites Include="$(_BlazorApplicationTrimmerDescriptorFile)" />
+ <FileWrites Include="$(_BlazorTypeGranularTrimmerDescriptorFile)" />
+ </ItemGroup>
+ </Target>
+
+ <Target Name="_ProcessPublishFilesForBlazor" DependsOnTargets="_ResolveBlazorWasmOutputs" AfterTargets="ILLink">
+
+ <!--
+ ResolvedFileToPublish.Culture is missing for satellite assemblies from project references.
+ Since we need the culture to correctly generate blazor.boot.json, we cross-reference the culture we calculate as part of _ResolveBlazorWasmOutputs
+ -->
+ <JoinItems Left="@(ResolvedFileToPublish)"
+ Right="@(_BlazorOutputWithTargetPath->HasMetadata('Culture'))"
+ LeftMetadata="*"
+ RightMetadata="Culture"
+ ItemSpecToUse="Left">
+ <Output TaskParameter="JoinResult" ItemName="_ResolvedSatelliteToPublish" />
+ </JoinItems>
+
+ <ItemGroup>
+ <ResolvedFileToPublish Remove="@(_ResolvedSatelliteToPublish)" />
+ <ResolvedFileToPublish Include="@(_ResolvedSatelliteToPublish)" />
+
+ <ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'%(Extension)' == '.a'" />
+
+ <!-- Remove dotnet.js from publish output -->
+ <ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.RelativePath)' == 'dotnet.js'" />
+
+ <!-- Retarget so that items are published to the wwwroot directory -->
+ <ResolvedFileToPublish
+ RelativePath="$(_BlazorOutputPath)%(ResolvedFileToPublish.RelativePath)"
+ Condition="'%(ResolvedFileToPublish.RelativePath)' != 'web.config' AND !$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))" />
+
+ <!-- Remove pdbs from the publish output -->
+ <ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'$(BlazorWebAssemblyEnableDebugging)' != 'true' AND '%(Extension)' == '.pdb'" />
+ </ItemGroup>
+
+ <ItemGroup Condition="'@(ResolvedFileToPublish->AnyHaveMetadataValue('RelativePath', 'web.config'))' != 'true'">
+ <ResolvedFileToPublish
+ Include="$(MSBuildThisFileDirectory)BlazorWasm.web.config"
+ ExcludeFromSingleFile="true"
+ CopyToPublishDirectory="PreserveNewest"
+ RelativePath="web.config" />
+ </ItemGroup>
+
+ <!-- Generate the publish boot json -->
+ <ItemGroup>
+ <_BlazorPublishBootResource
+ Include="@(ResolvedFileToPublish)"
+ Condition="$([System.String]::Copy('%(RelativePath)').Replace('\','/').StartsWith('wwwroot/_framework')) AND '%(Extension)' != '.a'" />
+ </ItemGroup>
+
+ <GetFileHash Files="@(_BlazorPublishBootResource)" Algorithm="SHA256" HashEncoding="base64">
+ <Output TaskParameter="Items" ItemName="_BlazorPublishBootResourceWithHash" />
+ </GetFileHash>
+
+ <GenerateBlazorWebAssemblyBootJson
+ AssemblyPath="@(IntermediateAssembly)"
+ Resources="@(_BlazorPublishBootResourceWithHash)"
+ DebugBuild="false"
+ LinkerEnabled="$(PublishTrimmed)"
+ CacheBootResources="$(BlazorCacheBootResources)"
+ OutputPath="$(IntermediateOutputPath)blazor.publish.boot.json"
+ ConfigurationFiles="@(_BlazorConfigFile)"
+ LazyLoadedAssemblies="@(BlazorWebAssemblyLazyLoad)" />
+
+ <ItemGroup>
+ <ResolvedFileToPublish
+ Include="$(IntermediateOutputPath)blazor.publish.boot.json"
+ RelativePath="$(_BlazorOutputPath)blazor.boot.json" />
+
+ <ResolvedFileToPublish
+ Include="@(_BlazorJSFile)"
+ RelativePath="$(_BlazorOutputPath)%(FileName)%(Extension)" />
+ </ItemGroup>
+ </Target>
+
+ <Target Name="_BlazorCompressPublishFiles" AfterTargets="_ProcessPublishFilesForBlazor" Condition="'$(BlazorEnableCompression)' != 'false'">
+ <PropertyGroup>
+ <_CompressedFileOutputPath>$(IntermediateOutputPath)brotli\</_CompressedFileOutputPath>
+ <_BlazorWebAssemblyBrotliIncremental>true</_BlazorWebAssemblyBrotliIncremental>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <_BrotliFileToCompress
+ Include="@(ResolvedFileToPublish)"
+ Condition="$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))" />
+ </ItemGroup>
+
+ <Message Text="Compressing Blazor WebAssembly publish artifacts. This may take a while..." Importance="High" />
+
+ <MakeDir Directories="$(_CompressedFileOutputPath)" Condition="!Exists('$(_CompressedFileOutputPath)')" />
+
+ <BrotliCompress
+ OutputDirectory="$(_CompressedFileOutputPath)"
+ FilesToCompress="@(_BrotliFileToCompress)"
+ CompressionLevel="$(_BlazorBrotliCompressionLevel)"
+ SkipIfOutputIsNewer="$(_BlazorWebAssemblyBrotliIncremental)"
+ ToolAssembly="$(_RazorSdkToolAssembly)">
+
+ <Output TaskParameter="CompressedFiles" ItemName="_BrotliCompressedFile" />
+ <Output TaskParameter="CompressedFiles" ItemName="FileWrites" />
+ </BrotliCompress>
+
+ <ItemGroup>
+ <ResolvedFileToPublish Include="@(_BrotliCompressedFile)" />
+ </ItemGroup>
+ </Target>
+
+ <Target Name="_SetupPublishSemaphore" BeforeTargets="PrepareForPublish">
+ <PropertyGroup>
+ <!--
+ Add marker that indicates Blazor WASM is doing a publish. This is used to identify when GetCopyToPublishDirectoryItems
+ is invoked as a result of a P2P reference.
+ -->
+ <_PublishingBlazorWasmProject>true</_PublishingBlazorWasmProject>
+ </PropertyGroup>
+ </Target>
+
+ <Target Name="_GetBlazorWasmFilesForPublishInner"
+ DependsOnTargets="_ResolveBlazorWasmOutputs;ComputeFilesToPublish"
+ Returns="@(ResolvedFileToPublish)" />
+
+ <Target Name="_GetBlazorWasmFilesForPublish" BeforeTargets="GetCopyToPublishDirectoryItems">
+ <MSBuild
+ Projects="$(MSBuildProjectFullPath)"
+ Targets="_GetBlazorWasmFilesForPublishInner"
+ Properties="BuildProjectReferences=false;ResolveAssemblyReferencesFindRelatedSatellites=true;_PublishingBlazorWasmProject=true"
+ RemoveProperties="NoBuild;RuntimeIdentifier"
+ BuildInParallel="$(BuildInParallel)"
+ Condition="'$(_PublishingBlazorWasmProject)' != 'true'">
+
+ <Output TaskParameter="TargetOutputs" ItemName="_ResolvedFileToPublish" />
+ </MSBuild>
+
+ <ItemGroup>
+ <AllPublishItemsFullPathWithTargetPath Include="@(_ResolvedFileToPublish->'%(FullPath)')">
+ <TargetPath>%(RelativePath)</TargetPath>
+ <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
+ </AllPublishItemsFullPathWithTargetPath>
+ </ItemGroup>
+ </Target>
+
+ <Target Name="_BlazorApplyLinkPreferencesToContent" BeforeTargets="AssignTargetPaths;ResolveCurrentProjectStaticWebAssetsInputs;ResolveStaticWebAssetsInputs" Returns="@(Content)">
+ <ItemGroup>
+ <Content
+ Condition="'%(Content.Link)' != '' AND '%(Content.CopyToPublishDirectory)' == '' AND $([System.String]::Copy('%(Content.Link)').Replace('\','/').StartsWith('wwwroot/'))"
+ CopyToPublishDirectory="PreserveNewest" />
+
+ </ItemGroup>
+ </Target>
+</Project>
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.StaticWebAssets.targets b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.StaticWebAssets.targets
index 9a66b1b926..71721b675d 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.StaticWebAssets.targets
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.StaticWebAssets.targets
@@ -269,7 +269,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<ItemGroup>
<StaticWebAsset
Include="@(_ReferencedProjectStaticWebAssets)"
- KeepMetadata="ContentRoot;BasePath;RelativePath;SourceId;SourceType" />
+ KeepMetadata="ContentRoot;BasePath;RelativePath;SourceId;SourceType;CopyToPublishDirectory" />
</ItemGroup>
</Target>
@@ -291,7 +291,7 @@ Copyright (c) .NET Foundation. All rights reserved.
</_ThisProjectStaticWebAsset>
- <StaticWebAsset Include="@(_ThisProjectStaticWebAsset->'%(FullPath)')" RemoveMetadata="CopyToPublishDirectory;ExcludeFromSingleFile">
+ <StaticWebAsset Include="@(_ThisProjectStaticWebAsset->'%(FullPath)')" RemoveMetadata="ExcludeFromSingleFile">
<!-- (Package, Project, '' (CurrentProject)) -->
<SourceType></SourceType>
<!-- Identifier describing the source, the package id, the project name, empty for the current project. -->
@@ -513,7 +513,7 @@ Copyright (c) .NET Foundation. All rights reserved.
-->
<_ExternalPublishStaticWebAsset
Include="%(StaticWebAsset.FullPath)"
- Condition="'%(SourceType)' != ''">
+ Condition="'%(SourceType)' != '' AND '%(StaticWebAsset.CopyToPublishDirectory)' != 'Never'">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<RelativePath>$([MSBuild]::MakeRelative('$(MSBuildProjectDirectory)','$([MSBuild]::NormalizePath('wwwroot\%(BasePath)\%(RelativePath)'))'))</RelativePath>
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.props b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.props
index 6fad4d5180..7e49bc4277 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.props
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.props
@@ -14,4 +14,5 @@ Copyright (c) .NET Foundation. All rights reserved.
<RazorSdkCurrentVersionProps>$(MSBuildThisFileDirectory)Sdk.Razor.CurrentVersion.props</RazorSdkCurrentVersionProps>
<RazorSdkCurrentVersionTargets>$(MSBuildThisFileDirectory)Sdk.Razor.CurrentVersion.targets</RazorSdkCurrentVersionTargets>
</PropertyGroup>
-</Project>
+
+</Project> \ No newline at end of file
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.props b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.props
index b7d17b206b..19e380c3a4 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.props
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.props
@@ -18,6 +18,8 @@ Copyright (c) .NET Foundation. All rights reserved.
Default properties for common Razor SDK behavior.
-->
<PropertyGroup>
+ <UsingMicrosoftNETSdkRazor>true</UsingMicrosoftNETSdkRazor>
+
<!--
Set to true to automatically include certain file types, such as .cshtml files, as content in the project.
When referenced via Microsoft.NET.Sdk.Web, this additionally includes all files under wwwroot, and any config files.
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets
index 0b6cf45554..62dc374582 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets
@@ -33,12 +33,14 @@ Copyright (c) .NET Foundation. All rights reserved.
<_RazorSdkTasksTFM Condition=" '$(MSBuildRuntimeType)' == 'Core'">net5.0</_RazorSdkTasksTFM>
<_RazorSdkTasksTFM Condition=" '$(_RazorSdkTasksTFM)' == ''">net46</_RazorSdkTasksTFM>
<RazorSdkBuildTasksAssembly>$(RazorSdkBuildTasksDirectoryRoot)$(_RazorSdkTasksTFM)\Microsoft.NET.Sdk.Razor.Tasks.dll</RazorSdkBuildTasksAssembly>
+ <_RazorSdkToolAssembly>$(RazorSdkDirectoryRoot)tools\netcoreapp3.0\rzc.dll</_RazorSdkToolAssembly>
</PropertyGroup>
<!-- Resolve the RazorLangVersion based on values imported or TFM. -->
<PropertyGroup>
<_TargetFrameworkVersionWithoutV>$(TargetFrameworkVersion.TrimStart('vV'))</_TargetFrameworkVersionWithoutV>
<_TargetingNETCoreApp30OrLater Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND '$(_TargetFrameworkVersionWithoutV)' >= '3.0'">true</_TargetingNETCoreApp30OrLater>
+ <_TargetingNET50OrLater Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND '$(_TargetFrameworkVersionWithoutV)' >= '5.0'">true</_TargetingNET50OrLater>
<!--
Infer the RazorLangVersion if no value was specified. When adding support for newer target frameworks, list newer language versions first.
@@ -354,6 +356,8 @@ Copyright (c) .NET Foundation. All rights reserved.
<Import Project="Microsoft.NET.Sdk.Razor.MvcApplicationPartsDiscovery.targets" Condition="'$(_TargetingNETCoreApp30OrLater)' == 'true'" />
+ <Import Project="Microsoft.NET.Sdk.Razor.Components.Wasm.targets" Condition="'$(_TargetingNET50OrLater)' == 'true' AND '$(UseBlazorWebAssembly)' == 'true'" />
+
<!--
These are the targets that actually do compilation using CSC, separated from the main file for ease of maintenance.
diff --git a/src/Components/WebAssembly/Build/test/BlazorReadSatelliteAssemblyFileTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/test/BlazorReadSatelliteAssemblyFileTest.cs
index 991d11f7da..3c73fb3036 100644
--- a/src/Components/WebAssembly/Build/test/BlazorReadSatelliteAssemblyFileTest.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/test/BlazorReadSatelliteAssemblyFileTest.cs
@@ -3,13 +3,12 @@
using System.Collections.Generic;
using System.IO;
-using System.Xml.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Moq;
using Xunit;
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
+namespace Microsoft.AspNetCore.Razor.Tasks
{
public class BlazorReadSatelliteAssemblyFileTest
{
diff --git a/src/Components/WebAssembly/Build/test/GenerateBlazorBootJsonTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/test/GenerateBlazorBootJsonTest.cs
index 5b95548d57..051c7c8bfd 100644
--- a/src/Components/WebAssembly/Build/test/GenerateBlazorBootJsonTest.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/test/GenerateBlazorBootJsonTest.cs
@@ -7,62 +7,61 @@ using System.Runtime.Serialization.Json;
using Microsoft.Build.Framework;
using Moq;
using Xunit;
-using BootJsonData = Microsoft.AspNetCore.Components.WebAssembly.Build.GenerateBlazorBootJson.BootJsonData;
-namespace Microsoft.AspNetCore.Components.WebAssembly.Build
+namespace Microsoft.AspNetCore.Razor.Tasks
{
- public class GenerateBlazorBootJsonTest
+ public class GenerateBlazorWebAssemblyBootJsonTest
{
[Fact]
public void GroupsResourcesByType()
{
// Arrange
- var taskInstance = new GenerateBlazorBootJson
+ var taskInstance = new GenerateBlazorWebAssemblyBootJson
{
AssemblyPath = "MyApp.Entrypoint.dll",
Resources = new[]
{
CreateResourceTaskItem(
- "assembly",
- name: "My.Assembly1.ext", // Can specify filename with no dir
- fileHash: "abcdefghikjlmnopqrstuvwxyz"),
+ ("FileName", "My.Assembly1"),
+ ("Extension", ".dll"),
+ ("FileHash", "abcdefghikjlmnopqrstuvwxyz")),
CreateResourceTaskItem(
- "assembly",
- name: "dir\\My.Assembly2.ext2", // Can specify Windows-style path
- fileHash: "012345678901234567890123456789"),
+ ("FileName", "My.Assembly2"),
+ ("Extension", ".dll"),
+ ("FileHash", "012345678901234567890123456789")),
CreateResourceTaskItem(
- "pdb",
- name: "otherdir/SomePdb.pdb", // Can specify Linux-style path
- fileHash: "pdbhashpdbhashpdbhash"),
+ ("FileName", "SomePdb"),
+ ("Extension", ".pdb"),
+ ("FileHash", "pdbhashpdbhashpdbhash")),
CreateResourceTaskItem(
- "pdb",
- name: "My.Assembly1.pdb",
- fileHash: "pdbdefghikjlmnopqrstuvwxyz"),
+ ("FileName", "My.Assembly1"),
+ ("Extension", ".pdb"),
+ ("FileHash", "pdbdefghikjlmnopqrstuvwxyz")),
CreateResourceTaskItem(
- "runtime",
- name: "some-runtime-file", // Can specify path with no extension
- fileHash: "runtimehashruntimehash"),
+ ("FileName", "some-runtime-file"),
+ ("FileHash", "runtimehashruntimehash"),
+ ("AssetType", "native")),
CreateResourceTaskItem(
- "satellite",
- name: "en-GB\\satellite-assembly1.ext",
- fileHash: "hashsatelliteassembly1",
+ ("FileName", "satellite-assembly1"),
+ ("Extension", ".dll"),
+ ("FileHash", "hashsatelliteassembly1"),
("Culture", "en-GB")),
CreateResourceTaskItem(
- "satellite",
- name: "fr/satellite-assembly2.dll",
- fileHash: "hashsatelliteassembly2",
+ ("FileName", "satellite-assembly2"),
+ ("Extension", ".dll"),
+ ("FileHash", "hashsatelliteassembly2"),
("Culture", "fr")),
CreateResourceTaskItem(
- "satellite",
- name: "en-GB\\satellite-assembly3.ext",
- fileHash: "hashsatelliteassembly3",
+ ("FileName", "satellite-assembly3"),
+ ("Extension", ".dll"),
+ ("FileHash", "hashsatelliteassembly3"),
("Culture", "en-GB")),
}
};
@@ -78,12 +77,12 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
var resources = parsedContent.resources.assembly;
Assert.Equal(2, resources.Count);
- Assert.Equal("sha256-abcdefghikjlmnopqrstuvwxyz", resources["My.Assembly1.ext"]);
- Assert.Equal("sha256-012345678901234567890123456789", resources["dir/My.Assembly2.ext2"]); // Paths are converted to use URL-style separators
+ Assert.Equal("sha256-abcdefghikjlmnopqrstuvwxyz", resources["My.Assembly1.dll"]);
+ Assert.Equal("sha256-012345678901234567890123456789", resources["My.Assembly2.dll"]);
resources = parsedContent.resources.pdb;
Assert.Equal(2, resources.Count);
- Assert.Equal("sha256-pdbhashpdbhashpdbhash", resources["otherdir/SomePdb.pdb"]);
+ Assert.Equal("sha256-pdbhashpdbhashpdbhash", resources["SomePdb.pdb"]);
Assert.Equal("sha256-pdbdefghikjlmnopqrstuvwxyz", resources["My.Assembly1.pdb"]);
resources = parsedContent.resources.runtime;
@@ -100,12 +99,12 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
kvp.Value.OrderBy(item => item.Key),
item =>
{
- Assert.Equal("en-GB/satellite-assembly1.ext", item.Key);
+ Assert.Equal("en-GB/satellite-assembly1.dll", item.Key);
Assert.Equal("sha256-hashsatelliteassembly1", item.Value);
},
item =>
{
- Assert.Equal("en-GB/satellite-assembly3.ext", item.Key);
+ Assert.Equal("en-GB/satellite-assembly3.dll", item.Key);
Assert.Equal("sha256-hashsatelliteassembly3", item.Value);
});
},
@@ -128,7 +127,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
public void CanSpecifyCacheBootResources(bool flagValue)
{
// Arrange
- var taskInstance = new GenerateBlazorBootJson { CacheBootResources = flagValue };
+ var taskInstance = new GenerateBlazorWebAssemblyBootJson { CacheBootResources = flagValue };
using var stream = new MemoryStream();
// Act
@@ -145,7 +144,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
public void CanSpecifyDebugBuild(bool flagValue)
{
// Arrange
- var taskInstance = new GenerateBlazorBootJson { DebugBuild = flagValue };
+ var taskInstance = new GenerateBlazorWebAssemblyBootJson { DebugBuild = flagValue };
using var stream = new MemoryStream();
// Act
@@ -162,7 +161,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
public void CanSpecifyLinkerEnabled(bool flagValue)
{
// Arrange
- var taskInstance = new GenerateBlazorBootJson { LinkerEnabled = flagValue };
+ var taskInstance = new GenerateBlazorWebAssemblyBootJson { LinkerEnabled = flagValue };
using var stream = new MemoryStream();
// Act
@@ -182,19 +181,13 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Build
return (BootJsonData)serializer.ReadObject(stream);
}
- private static ITaskItem CreateResourceTaskItem(string type, string name, string fileHash, params (string key, string value)[] values)
+ private static ITaskItem CreateResourceTaskItem(params (string key, string value)[] values)
{
var mock = new Mock<ITaskItem>();
- mock.Setup(m => m.GetMetadata("BootManifestResourceType")).Returns(type);
- mock.Setup(m => m.GetMetadata("BootManifestResourceName")).Returns(name);
- mock.Setup(m => m.GetMetadata("Integrity")).Returns(fileHash);
- if (values != null)
+ foreach (var (key, value) in values)
{
- foreach (var (key, value) in values)
- {
- mock.Setup(m => m.GetMetadata(key)).Returns(value);
- }
+ mock.Setup(m => m.GetMetadata(key)).Returns(value);
}
return mock.Object;
}
diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/test/GenerateStaticWebAssetsPropsFileTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/test/GenerateStaticWebAssetsPropsFileTest.cs
index d7f4b8206b..2525e15626 100644
--- a/src/Razor/Microsoft.NET.Sdk.Razor/test/GenerateStaticWebAssetsPropsFileTest.cs
+++ b/src/Razor/Microsoft.NET.Sdk.Razor/test/GenerateStaticWebAssetsPropsFileTest.cs
@@ -3,7 +3,6 @@
using System.Collections.Generic;
using System.IO;
-using Microsoft.AspNetCore.Razor.Tasks;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Moq;
diff --git a/src/Razor/test/testassets/Directory.Build.props b/src/Razor/test/testassets/Directory.Build.props
index ece4b1e256..ced785009b 100644
--- a/src/Razor/test/testassets/Directory.Build.props
+++ b/src/Razor/test/testassets/Directory.Build.props
@@ -16,6 +16,7 @@
<RepoRoot Condition="'$(BuildingTestAppsIndependently)' == 'true' AND '$(RepoRoot)' == ''">$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, 'global.json'))\</RepoRoot>
<RazorSdkArtifactsDirectory>$(RepoRoot)artifacts\bin\Microsoft.NET.Sdk.Razor\</RazorSdkArtifactsDirectory>
+ <BlazorWebAssemblyJSPath>$(MSBuildThisFileDirectory)blazor.webassembly.js</BlazorWebAssemblyJSPath>
</PropertyGroup>
<Import Project="$(RepoRoot)eng\Versions.props" />
@@ -26,6 +27,9 @@
<!-- Working around an issue in XDT transforms -->
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
+
+ <!-- Turn down the compression level for brotli -->
+ <_BlazorBrotliCompressionLevel>NoCompression</_BlazorBrotliCompressionLevel>
</PropertyGroup>
<!-- Don't use the server when building in place. This locks up rzc.dll -->
@@ -37,7 +41,6 @@
<!-- Have the SDK treat the MvcShim as an MVC assembly -->
<_MvcAssemblyName Include="Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib" />
</ItemGroup>
-
<ItemGroup Condition="$(BuildingTestAppsIndependently) == 'false'">
<PackageReference Include="Microsoft.Net.Compilers.Toolset"
Version="$(MicrosoftNetCompilersToolsetPackageVersion)"
diff --git a/src/Components/WebAssembly/Build/testassets/LinkBaseToWebRoot/js/LinkedScript.js b/src/Razor/test/testassets/LinkBaseToWebRoot/js/LinkedScript.js
index 5f282702bb..5f282702bb 100644
--- a/src/Components/WebAssembly/Build/testassets/LinkBaseToWebRoot/js/LinkedScript.js
+++ b/src/Razor/test/testassets/LinkBaseToWebRoot/js/LinkedScript.js
diff --git a/src/Razor/test/testassets/RestoreTestProjects/RestoreTestProjects.csproj b/src/Razor/test/testassets/RestoreTestProjects/RestoreTestProjects.csproj
index d6d2bcc427..dae219047b 100644
--- a/src/Razor/test/testassets/RestoreTestProjects/RestoreTestProjects.csproj
+++ b/src/Razor/test/testassets/RestoreTestProjects/RestoreTestProjects.csproj
@@ -7,6 +7,9 @@
<ProjectReference Include="..\SimpleMvc21\SimpleMvc21.csproj" />
<ProjectReference Include="..\SimpleMvc31\SimpleMvc31.csproj" />
<ProjectReference Include="..\blazor31\blazor31.csproj" />
+ <ProjectReference Include="..\blazorhosted\blazorhosted.csproj" />
+ <ProjectReference Include="..\blazorhosted-rid\blazorhosted-rid.csproj" />
+ <ProjectReference Include="..\blazorwasm\blazorwasm.csproj" />
<ProjectReference Include="..\ClassLibraryMvc21\ClassLibraryMvc21.csproj" />
<ProjectReference Include="..\AppWithP2PReference\AppWithP2PReference.csproj" />
<ProjectReference Include="..\AppWithPackageAndP2PReferenceAndRID\AppWithPackageAndP2PReferenceAndRID.csproj" />
diff --git a/src/Razor/test/testassets/SimpleMvc21/SimpleMvc21.csproj b/src/Razor/test/testassets/SimpleMvc21/SimpleMvc21.csproj
index 2f53950aa6..292a0a83df 100644
--- a/src/Razor/test/testassets/SimpleMvc21/SimpleMvc21.csproj
+++ b/src/Razor/test/testassets/SimpleMvc21/SimpleMvc21.csproj
@@ -7,6 +7,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
+ <RazorSdkDirectoryRoot>$(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\</RazorSdkDirectoryRoot>
</PropertyGroup>
<!-- Test Placeholder -->
diff --git a/src/Razor/test/testassets/blazor.webassembly.js b/src/Razor/test/testassets/blazor.webassembly.js
new file mode 100644
index 0000000000..84362ca046
--- /dev/null
+++ b/src/Razor/test/testassets/blazor.webassembly.js
@@ -0,0 +1 @@
+Test file \ No newline at end of file
diff --git a/src/Razor/test/testassets/blazorhosted-rid/Program.cs b/src/Razor/test/testassets/blazorhosted-rid/Program.cs
new file mode 100644
index 0000000000..cb0046ec11
--- /dev/null
+++ b/src/Razor/test/testassets/blazorhosted-rid/Program.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace blazorhosted.Server
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ Console.WriteLine(typeof(string));
+ }
+ }
+}
diff --git a/src/Razor/test/testassets/blazorhosted-rid/blazorhosted-rid.csproj b/src/Razor/test/testassets/blazorhosted-rid/blazorhosted-rid.csproj
new file mode 100644
index 0000000000..1e14923fb3
--- /dev/null
+++ b/src/Razor/test/testassets/blazorhosted-rid/blazorhosted-rid.csproj
@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+ <PropertyGroup>
+ <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
+ <RazorSdkDirectoryRoot>$(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\</RazorSdkDirectoryRoot>
+ <!--
+ Specify the RID in the project file to allow the runtime pack to be restored during repo restore.
+ We do not want the rid-specific package to be restored as part of the test.
+ -->
+ <RuntimeIdentifier>linux-x64</RuntimeIdentifier>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\blazorwasm\blazorwasm.csproj" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <FrameworkReference Remove="Microsoft.AspNetCore.App" />
+ <KnownFrameworkReference Remove="Microsoft.AspNetCore.App" />
+ </ItemGroup>
+
+</Project>
diff --git a/src/Components/WebAssembly/Build/testassets/blazorhosted/Program.cs b/src/Razor/test/testassets/blazorhosted/Program.cs
index a90f4db291..a90f4db291 100644
--- a/src/Components/WebAssembly/Build/testassets/blazorhosted/Program.cs
+++ b/src/Razor/test/testassets/blazorhosted/Program.cs
diff --git a/src/Razor/test/testassets/blazorhosted/blazorhosted.csproj b/src/Razor/test/testassets/blazorhosted/blazorhosted.csproj
new file mode 100644
index 0000000000..28c8a47ce5
--- /dev/null
+++ b/src/Razor/test/testassets/blazorhosted/blazorhosted.csproj
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+ <PropertyGroup>
+ <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
+ <RazorSdkDirectoryRoot>$(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\</RazorSdkDirectoryRoot>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\blazorwasm\blazorwasm.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/src/Components/WebAssembly/Build/testassets/standalone/App.razor b/src/Razor/test/testassets/blazorwasm/App.razor
index eba23da9b5..eba23da9b5 100644
--- a/src/Components/WebAssembly/Build/testassets/standalone/App.razor
+++ b/src/Razor/test/testassets/blazorwasm/App.razor
diff --git a/src/Components/WebAssembly/Build/testassets/standalone/LinkToWebRoot/css/app.css b/src/Razor/test/testassets/blazorwasm/LinkToWebRoot/css/app.css
index 6c9631b4e1..6c9631b4e1 100644
--- a/src/Components/WebAssembly/Build/testassets/standalone/LinkToWebRoot/css/app.css
+++ b/src/Razor/test/testassets/blazorwasm/LinkToWebRoot/css/app.css
diff --git a/src/Components/WebAssembly/Build/testassets/standalone/Pages/Index.razor b/src/Razor/test/testassets/blazorwasm/Pages/Index.razor
index 16dac31925..16dac31925 100644
--- a/src/Components/WebAssembly/Build/testassets/standalone/Pages/Index.razor
+++ b/src/Razor/test/testassets/blazorwasm/Pages/Index.razor
diff --git a/src/Components/WebAssembly/Build/testassets/standalone/Program.cs b/src/Razor/test/testassets/blazorwasm/Program.cs
index 7d2cb4eeea..4b20dea9de 100644
--- a/src/Components/WebAssembly/Build/testassets/standalone/Program.cs
+++ b/src/Razor/test/testassets/blazorwasm/Program.cs
@@ -6,6 +6,7 @@ namespace standalone
{
public static void Main(string[] args)
{
+ GC.KeepAlive(typeof(System.Text.Json.JsonSerializer));
GC.KeepAlive(typeof(RazorClassLibrary.Class1));
#if REFERENCE_classlibrarywithsatelliteassemblies
GC.KeepAlive(typeof(classlibrarywithsatelliteassemblies.Class1));
diff --git a/src/Components/WebAssembly/Build/testassets/standalone/Resources.ja.resx.txt b/src/Razor/test/testassets/blazorwasm/Resources.ja.resx.txt
index aabe84e3c0..aabe84e3c0 100644
--- a/src/Components/WebAssembly/Build/testassets/standalone/Resources.ja.resx.txt
+++ b/src/Razor/test/testassets/blazorwasm/Resources.ja.resx.txt
diff --git a/src/Components/WebAssembly/Build/testassets/standalone/_Imports.razor b/src/Razor/test/testassets/blazorwasm/_Imports.razor
index 129b440e86..129b440e86 100644
--- a/src/Components/WebAssembly/Build/testassets/standalone/_Imports.razor
+++ b/src/Razor/test/testassets/blazorwasm/_Imports.razor
diff --git a/src/Razor/test/testassets/blazorwasm/blazorwasm.csproj b/src/Razor/test/testassets/blazorwasm/blazorwasm.csproj
new file mode 100644
index 0000000000..724a4365b5
--- /dev/null
+++ b/src/Razor/test/testassets/blazorwasm/blazorwasm.csproj
@@ -0,0 +1,45 @@
+<Project Sdk="Microsoft.NET.Sdk.Razor">
+ <PropertyGroup>
+ <TargetFramework>net5.0</TargetFramework>
+ <UseBlazorWebAssembly>true</UseBlazorWebAssembly>
+ <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
+ <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
+ <RazorSdkDirectoryRoot>$(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\</RazorSdkDirectoryRoot>
+ <ServiceWorkerAssetsManifest>custom-service-worker-assets.js</ServiceWorkerAssetsManifest>
+ </PropertyGroup>
+
+ <!-- Test Placeholder -->
+
+ <PropertyGroup Condition="'$(RunningAsTest)' == ''">
+ <!-- We don't want to run build server when not running as tests. -->
+ <UseRazorBuildServer>false</UseRazorBuildServer>
+ </PropertyGroup>
+
+ <PropertyGroup Condition="'$(BinariesRoot)'==''">
+ <!-- In test scenarios $(BinariesRoot) is defined in a generated Directory.Build.props file -->
+ <BinariesRoot>$(RepoRoot)artifacts\bin\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib\$(Configuration)\netstandard2.0\</BinariesRoot>
+ </PropertyGroup>
+
+ <!-- DO NOT add addition references here. This is meant to simulate a non-MVC library -->
+ <ItemGroup Condition="'$(BinariesRoot)'!=''">
+ <Reference Include="$(BinariesRoot)\Microsoft.AspNetCore.Razor.Test.ComponentShim.dll"/>
+ <ProjectReference Include="..\razorclasslibrary\RazorClassLibrary.csproj" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <!-- These assets should be treated as static web assets for publish purposes -->
+ <Content Include="..\LinkBaseToWebRoot\**\*.js">
+ <LinkBase>wwwroot\</LinkBase>
+ </Content>
+
+ <!-- This asset should be ignored as a static web assets as it defines CopyToPublishDirectory="Never" -->
+ <Content Update="wwwroot\css\app.css" CopyToPublishDirectory="Never" />
+
+ <!-- This asset should be treated as a static web asset and copied into the right location defined by its link attribute. -->
+ <Content Include="LinkToWebRoot\css\app.css" Link="wwwroot\css\app.css" />
+
+ <!-- The content from my-prod-service-worker.js should be published under the name my-service-worker.js -->
+ <ServiceWorker Include="wwwroot\serviceworkers\my-service-worker.js" PublishedContent="wwwroot\serviceworkers\my-prod-service-worker.js" />
+ </ItemGroup>
+
+</Project>
diff --git a/src/Components/WebAssembly/Build/testassets/standalone/wwwroot/Fake-License.txt b/src/Razor/test/testassets/blazorwasm/wwwroot/Fake-License.txt
index 5f282702bb..5f282702bb 100644
--- a/src/Components/WebAssembly/Build/testassets/standalone/wwwroot/Fake-License.txt
+++ b/src/Razor/test/testassets/blazorwasm/wwwroot/Fake-License.txt
diff --git a/src/Components/WebAssembly/Build/testassets/standalone/wwwroot/css/app.css b/src/Razor/test/testassets/blazorwasm/wwwroot/css/app.css
index fc64a12376..fc64a12376 100644
--- a/src/Components/WebAssembly/Build/testassets/standalone/wwwroot/css/app.css
+++ b/src/Razor/test/testassets/blazorwasm/wwwroot/css/app.css
diff --git a/src/Components/WebAssembly/Build/testassets/standalone/wwwroot/index.html b/src/Razor/test/testassets/blazorwasm/wwwroot/index.html
index bbfa66c41a..bbfa66c41a 100644
--- a/src/Components/WebAssembly/Build/testassets/standalone/wwwroot/index.html
+++ b/src/Razor/test/testassets/blazorwasm/wwwroot/index.html
diff --git a/src/Components/WebAssembly/Build/testassets/standalone/wwwroot/serviceworkers/my-prod-service-worker.js b/src/Razor/test/testassets/blazorwasm/wwwroot/serviceworkers/my-prod-service-worker.js
index a2ecc1b349..a2ecc1b349 100644
--- a/src/Components/WebAssembly/Build/testassets/standalone/wwwroot/serviceworkers/my-prod-service-worker.js
+++ b/src/Razor/test/testassets/blazorwasm/wwwroot/serviceworkers/my-prod-service-worker.js
diff --git a/src/Components/WebAssembly/Build/testassets/standalone/wwwroot/serviceworkers/my-service-worker.js b/src/Razor/test/testassets/blazorwasm/wwwroot/serviceworkers/my-service-worker.js
index c42d1c8475..c42d1c8475 100644
--- a/src/Components/WebAssembly/Build/testassets/standalone/wwwroot/serviceworkers/my-service-worker.js
+++ b/src/Razor/test/testassets/blazorwasm/wwwroot/serviceworkers/my-service-worker.js
diff --git a/src/Components/WebAssembly/Build/testassets/classlibrarywithsatelliteassemblies/Class1.cs b/src/Razor/test/testassets/classlibrarywithsatelliteassemblies/Class1.cs
index 944699cdb3..944699cdb3 100644
--- a/src/Components/WebAssembly/Build/testassets/classlibrarywithsatelliteassemblies/Class1.cs
+++ b/src/Razor/test/testassets/classlibrarywithsatelliteassemblies/Class1.cs
diff --git a/src/Components/WebAssembly/Build/testassets/classlibrarywithsatelliteassemblies/Resources.es-ES.resx b/src/Razor/test/testassets/classlibrarywithsatelliteassemblies/Resources.es-ES.resx
index 0ab8f0ddfb..0ab8f0ddfb 100644
--- a/src/Components/WebAssembly/Build/testassets/classlibrarywithsatelliteassemblies/Resources.es-ES.resx
+++ b/src/Razor/test/testassets/classlibrarywithsatelliteassemblies/Resources.es-ES.resx
diff --git a/src/Components/WebAssembly/Build/testassets/classlibrarywithsatelliteassemblies/classlibrarywithsatelliteassemblies.csproj b/src/Razor/test/testassets/classlibrarywithsatelliteassemblies/classlibrarywithsatelliteassemblies.csproj
index 7081842748..f1a186fb94 100644
--- a/src/Components/WebAssembly/Build/testassets/classlibrarywithsatelliteassemblies/classlibrarywithsatelliteassemblies.csproj
+++ b/src/Razor/test/testassets/classlibrarywithsatelliteassemblies/classlibrarywithsatelliteassemblies.csproj
@@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<RazorLangVersion>3.0</RazorLangVersion>
+ <RazorSdkDirectoryRoot>$(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\</RazorSdkDirectoryRoot>
</PropertyGroup>
<ItemGroup>
diff --git a/src/Components/WebAssembly/Build/testassets/razorclasslibrary/Class1.cs b/src/Razor/test/testassets/razorclasslibrary/Class1.cs
index fb55605ff4..fb55605ff4 100644
--- a/src/Components/WebAssembly/Build/testassets/razorclasslibrary/Class1.cs
+++ b/src/Razor/test/testassets/razorclasslibrary/Class1.cs
diff --git a/src/Components/WebAssembly/Build/testassets/razorclasslibrary/RazorClassLibrary.csproj b/src/Razor/test/testassets/razorclasslibrary/RazorClassLibrary.csproj
index 94e866815d..9480a0542e 100644
--- a/src/Components/WebAssembly/Build/testassets/razorclasslibrary/RazorClassLibrary.csproj
+++ b/src/Razor/test/testassets/razorclasslibrary/RazorClassLibrary.csproj
@@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<RazorLangVersion>3.0</RazorLangVersion>
+ <RazorSdkDirectoryRoot>$(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\</RazorSdkDirectoryRoot>
</PropertyGroup>
</Project>
diff --git a/src/Components/WebAssembly/Build/testassets/razorclasslibrary/wwwroot/styles.css b/src/Razor/test/testassets/razorclasslibrary/wwwroot/styles.css
index 5f282702bb..5f282702bb 100644
--- a/src/Components/WebAssembly/Build/testassets/razorclasslibrary/wwwroot/styles.css
+++ b/src/Razor/test/testassets/razorclasslibrary/wwwroot/styles.css
diff --git a/src/Components/WebAssembly/Build/testassets/razorclasslibrary/wwwroot/wwwroot/exampleJsInterop.js b/src/Razor/test/testassets/razorclasslibrary/wwwroot/wwwroot/exampleJsInterop.js
index e69de29bb2..e69de29bb2 100644
--- a/src/Components/WebAssembly/Build/testassets/razorclasslibrary/wwwroot/wwwroot/exampleJsInterop.js
+++ b/src/Razor/test/testassets/razorclasslibrary/wwwroot/wwwroot/exampleJsInterop.js