Merge pull request #23282 from dotnet-maestro-bot/merge/release/5.0-preview7-to-master

[automated] Merge branch 'release/5.0-preview7' => 'master'
This commit is contained in:
msftbot[bot] 2020-06-24 04:44:35 +00:00 committed by GitHub
commit 0d8d4e709c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
162 changed files with 2914 additions and 6704 deletions

View File

@ -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" />

View File

@ -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}

View File

@ -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",

View File

@ -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'">

File diff suppressed because one or more lines are too long

View File

@ -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()));

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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();
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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}\"";
}
}

View File

@ -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
}
}

View File

@ -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; }
}
}
}

View File

@ -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
}
}

View File

@ -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")));
}
}
}

View File

@ -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; }
}
}
}

View File

@ -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;
}
}
}

View File

@ -1,7 +0,0 @@
<Project>
<Import Project="$(MSBuildThisFileDirectory)..\..\targets\All.props" />
<PropertyGroup>
<ReferencesComponentsWebAssemblyBuild>true</ReferencesComponentsWebAssemblyBuild>
</PropertyGroup>
</Project>

View File

@ -1,3 +0,0 @@
<Project>
<Import Project="$(MSBuildThisFileDirectory)..\..\targets\All.targets" />
</Project>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -1,15 +0,0 @@
<Project>
<PropertyGroup>
<ResolveStaticWebAssetsInputsDependsOn>
$(ResolveStaticWebAssetsInputsDependsOn);
_BlazorApplyLinkPreferencesToStaticWebAssets;
_ResolveBlazorGeneratedAssets;
</ResolveStaticWebAssetsInputsDependsOn>
<GetCurrentProjectStaticWebAssetsDependsOn>
$(GetCurrentProjectStaticWebAssetsDependsOn);
_BlazorApplyLinkPreferencesToStaticWebAssets;
_ResolveBlazorGeneratedAssets;
</GetCurrentProjectStaticWebAssetsDependsOn>
</PropertyGroup>
</Project>

View File

@ -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>

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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 });
}
}
}

View File

@ -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();
}
}

View File

@ -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; }
}
}
}

View File

@ -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; }
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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";
}
}
}

View File

@ -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>

View File

@ -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();
}
}
}
}
}

View File

@ -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>

View File

@ -1,2 +0,0 @@
<Project>
</Project>

View File

@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\standalone\standalone.csproj" />
</ItemGroup>
</Project>

View File

@ -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>

View File

@ -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>

View File

@ -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; }
}
}
}

View File

@ -1,3 +0,0 @@
{
"rollForwardOnNoCandidateFx": 2
}

View File

@ -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>

View File

@ -0,0 +1,5 @@
<Project>
<PropertyGroup>
<BlazorWebAssemblyJSPath>$(MSBuildThisFileDirectory)blazor.webassembly.js</BlazorWebAssemblyJSPath>
</PropertyGroup>
</Project>

View File

@ -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>

View File

@ -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>

View File

@ -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();
}
}

View File

@ -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");
});
}
}
}

View File

@ -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>

View File

@ -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);
}
})();

View File

@ -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"))}'";
}
}

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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()
{
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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" />

View File

@ -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")));
}

View File

@ -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);
}
}
}

View File

@ -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)
{

View File

@ -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,

View File

@ -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)

View File

@ -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");
}

View File

@ -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);

View File

@ -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>

View File

@ -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);

View File

@ -258,4 +258,4 @@ function receiveDotNetObjectByRefAsync(incomingData) {
testDto: testDto
};
});
}
}

View File

@ -1,8 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RazorLangVersion>3.0</RazorLangVersion>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -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">

View File

@ -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");

View File

@ -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>

View File

@ -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);

View File

@ -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'" />

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>${DefaultNetCoreTargetFramework}</TargetFramework>
</PropertyGroup>
</Project>

View File

@ -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" />

View File

@ -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>

View File

@ -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>

View File

@ -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; }

View File

@ -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);
}
}
}

View File

@ -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; }

View File

@ -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);

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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");

View File

@ -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");

View File

@ -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

View File

@ -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)

View File

@ -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)
{

Some files were not shown because too many files have changed in this diff Show More