Merge branch 'release/5.0' into prkrishn/nullability-feedback

This commit is contained in:
Pranav K 2020-08-26 16:38:48 -07:00 committed by GitHub
commit 87a51a358a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
492 changed files with 16117 additions and 4416 deletions

View File

@ -28,7 +28,7 @@ jobs:
# Test this script using changes in a fork
repository: 'dotnet/runtime'
path: runtime
ref: release/5.0-rc1
ref: release/5.0
- name: Copy
shell: cmd
working-directory: .\runtime\src\libraries\Common\src\System\Net\Http\aspnetcore\

View File

@ -1397,14 +1397,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sockets.BindTests", "src\Se
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "http2cat", "src\Servers\Kestrel\samples\http2cat\http2cat.csproj", "{8BDEC645-73BD-453B-8A5C-D616BC4EA08D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuicSampleApp", "src\Servers\Kestrel\samples\QuicSampleApp\QuicSampleApp.csproj", "{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Transport.Quic", "Transport.Quic", "{EE9D0952-6060-4723-B329-94A2950A6762}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Experimental.Quic", "src\Servers\Kestrel\Transport.Quic\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Experimental.Quic.csproj", "{132D43A2-067A-4E24-A520-45B9F14DCB8E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuicSampleClient", "src\Servers\Kestrel\samples\QuicSampleClient\QuicSampleClient.csproj", "{FA8D7CA4-C33B-4409-865F-54192BAC59A4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Http3SampleApp", "src\Servers\Kestrel\samples\Http3SampleApp\Http3SampleApp.csproj", "{2EC4E939-513F-44CD-A956-498966EAC929}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpStress", "src\Servers\Kestrel\stress\HttpStress.csproj", "{987E1C29-F124-40C8-8E6F-1B2B6A4CB62A}"
@ -1423,13 +1419,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Compon
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sdk", "Sdk", "{FED4267E-E5E4-49C5-98DB-8B3F203596EE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.NET.Sdk.BlazorWebAssembly", "src\Components\WebAssembly\Sdk\src\Microsoft.NET.Sdk.BlazorWebAssembly.csproj", "{6B2734BF-C61D-4889-ABBF-456A4075D59B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.BlazorWebAssembly", "src\Components\WebAssembly\Sdk\src\Microsoft.NET.Sdk.BlazorWebAssembly.csproj", "{6B2734BF-C61D-4889-ABBF-456A4075D59B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.NET.Sdk.BlazorWebAssembly.Tests", "src\Components\WebAssembly\Sdk\test\Microsoft.NET.Sdk.BlazorWebAssembly.Tests.csproj", "{83371889-9A3E-4D16-AE77-EB4F83BC6374}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.BlazorWebAssembly.Tests", "src\Components\WebAssembly\Sdk\test\Microsoft.NET.Sdk.BlazorWebAssembly.Tests.csproj", "{83371889-9A3E-4D16-AE77-EB4F83BC6374}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests", "src\Components\WebAssembly\Sdk\integrationtests\Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests.csproj", "{525EBCB4-A870-470B-BC90-845306C337D1}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests", "src\Components\WebAssembly\Sdk\integrationtests\Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests.csproj", "{525EBCB4-A870-470B-BC90-845306C337D1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.NET.Sdk.BlazorWebAssembly.Tools", "src\Components\WebAssembly\Sdk\tools\Microsoft.NET.Sdk.BlazorWebAssembly.Tools.csproj", "{175E5CD8-92D4-46BB-882E-3A930D3302D4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.BlazorWebAssembly.Tools", "src\Components\WebAssembly\Sdk\tools\Microsoft.NET.Sdk.BlazorWebAssembly.Tools.csproj", "{175E5CD8-92D4-46BB-882E-3A930D3302D4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{6126DCE4-9692-4EE2-B240-C65743572995}"
EndProject
@ -1455,7 +1451,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropClient", "src\Grpc\t
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropWebsite", "src\Grpc\test\testassets\InteropWebsite\InteropWebsite.csproj", "{19189670-E206-471D-94F8-7D3D545E5020}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wasm.Performance.ConsoleHost", "src\Components\benchmarkapps\Wasm.Performance\ConsoleHost\Wasm.Performance.ConsoleHost.csproj", "{E9408723-E6A9-4715-B906-3B25B0238ABA}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Performance.ConsoleHost", "src\Components\benchmarkapps\Wasm.Performance\ConsoleHost\Wasm.Performance.ConsoleHost.csproj", "{E9408723-E6A9-4715-B906-3B25B0238ABA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "src\Servers\IIS\IIS\test\testassets\InProcessWebSite\InProcessWebSite.csproj", "{8DA61885-B95E-4BA1-A752-C79B6597FC44}"
EndProject
@ -1483,6 +1479,36 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Watch.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Watch.BrowserRefresh.Tests", "src\Tools\dotnet-watch\BrowserRefresh\test\Microsoft.AspNetCore.Watch.BrowserRefresh.Tests.csproj", "{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{7D2B0799-A634-42AC-AE77-5D167BA51389}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostedInAspNet.Client", "src\Components\WebAssembly\testassets\HostedInAspNet.Client\HostedInAspNet.Client.csproj", "{9788C76F-658B-4441-88F8-22C6B86FAD27}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostedInAspNet.Server", "src\Components\WebAssembly\testassets\HostedInAspNet.Server\HostedInAspNet.Server.csproj", "{1970D5CD-D9A4-4673-A297-179BB04199F4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StandaloneApp", "src\Components\WebAssembly\testassets\StandaloneApp\StandaloneApp.csproj", "{A40350FE-4334-4007-B1C3-6BEB1B070309}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Authentication.Client", "src\Components\WebAssembly\testassets\Wasm.Authentication.Client\Wasm.Authentication.Client.csproj", "{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Authentication.Server", "src\Components\WebAssembly\testassets\Wasm.Authentication.Server\Wasm.Authentication.Server.csproj", "{FE5290C7-45DA-46F8-BD74-698E7A161DD6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Authentication.Shared", "src\Components\WebAssembly\testassets\Wasm.Authentication.Shared\Wasm.Authentication.Shared.csproj", "{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HealthChecks", "HealthChecks", "{C1E7F837-6988-43E2-9E1C-7302DB484F99}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2A91479A-4ABE-4BB7-9A5E-CA3B9CCFC69E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{7CB09412-C9B0-47E8-A8C3-311AA4CFDE04}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Abstractions", "Abstractions", "{22D7D74B-565D-4047-97B4-F149B1A13350}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions", "src\HealthChecks\Abstractions\src\Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj", "{B06040BC-DA28-4923-8CAC-20EB517D471B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Diagnostics.HealthChecks", "src\HealthChecks\HealthChecks\src\Microsoft.Extensions.Diagnostics.HealthChecks.csproj", "{55CACC1F-FE96-47C8-8073-91F4CAA55C75}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Diagnostics.HealthChecks.Tests", "src\HealthChecks\HealthChecks\test\Microsoft.Extensions.Diagnostics.HealthChecks.Tests.csproj", "{7509AA1E-3093-4BEE-984F-E11579E98A11}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.JSInterop.Tests", "src\JSInterop\Microsoft.JSInterop\test\Microsoft.JSInterop.Tests.csproj", "{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -6653,18 +6679,6 @@ Global
{8BDEC645-73BD-453B-8A5C-D616BC4EA08D}.Release|x64.Build.0 = Release|Any CPU
{8BDEC645-73BD-453B-8A5C-D616BC4EA08D}.Release|x86.ActiveCfg = Release|Any CPU
{8BDEC645-73BD-453B-8A5C-D616BC4EA08D}.Release|x86.Build.0 = Release|Any CPU
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Debug|x64.ActiveCfg = Debug|Any CPU
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Debug|x64.Build.0 = Debug|Any CPU
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Debug|x86.ActiveCfg = Debug|Any CPU
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Debug|x86.Build.0 = Debug|Any CPU
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Release|Any CPU.Build.0 = Release|Any CPU
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Release|x64.ActiveCfg = Release|Any CPU
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Release|x64.Build.0 = Release|Any CPU
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Release|x86.ActiveCfg = Release|Any CPU
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D}.Release|x86.Build.0 = Release|Any CPU
{132D43A2-067A-4E24-A520-45B9F14DCB8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{132D43A2-067A-4E24-A520-45B9F14DCB8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{132D43A2-067A-4E24-A520-45B9F14DCB8E}.Debug|x64.ActiveCfg = Debug|Any CPU
@ -6677,18 +6691,6 @@ Global
{132D43A2-067A-4E24-A520-45B9F14DCB8E}.Release|x64.Build.0 = Release|Any CPU
{132D43A2-067A-4E24-A520-45B9F14DCB8E}.Release|x86.ActiveCfg = Release|Any CPU
{132D43A2-067A-4E24-A520-45B9F14DCB8E}.Release|x86.Build.0 = Release|Any CPU
{FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Debug|x64.ActiveCfg = Debug|Any CPU
{FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Debug|x64.Build.0 = Debug|Any CPU
{FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Debug|x86.ActiveCfg = Debug|Any CPU
{FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Debug|x86.Build.0 = Debug|Any CPU
{FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Release|Any CPU.Build.0 = Release|Any CPU
{FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Release|x64.ActiveCfg = Release|Any CPU
{FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Release|x64.Build.0 = Release|Any CPU
{FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Release|x86.ActiveCfg = Release|Any CPU
{FA8D7CA4-C33B-4409-865F-54192BAC59A4}.Release|x86.Build.0 = Release|Any CPU
{2EC4E939-513F-44CD-A956-498966EAC929}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2EC4E939-513F-44CD-A956-498966EAC929}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2EC4E939-513F-44CD-A956-498966EAC929}.Debug|x64.ActiveCfg = Debug|Any CPU
@ -6809,30 +6811,6 @@ Global
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Release|x64.Build.0 = Release|Any CPU
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Release|x86.ActiveCfg = Release|Any CPU
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Release|x86.Build.0 = Release|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x64.ActiveCfg = Debug|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x64.Build.0 = Debug|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x86.ActiveCfg = Debug|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x86.Build.0 = Debug|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|Any CPU.Build.0 = Release|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x64.ActiveCfg = Release|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x64.Build.0 = Release|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x86.ActiveCfg = Release|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x86.Build.0 = Release|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x64.ActiveCfg = Debug|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x64.Build.0 = Debug|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x86.ActiveCfg = Debug|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x86.Build.0 = Debug|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|Any CPU.Build.0 = Release|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x64.ActiveCfg = Release|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x64.Build.0 = Release|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x86.ActiveCfg = Release|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x86.Build.0 = Release|Any CPU
{46FB7E93-1294-4068-B80A-D4864F78277A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{46FB7E93-1294-4068-B80A-D4864F78277A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{46FB7E93-1294-4068-B80A-D4864F78277A}.Debug|x64.ActiveCfg = Debug|Any CPU
@ -7071,6 +7049,150 @@ Global
{7E268085-1046-4362-80CB-2977FF826DCA}.Release|x64.Build.0 = Release|Any CPU
{7E268085-1046-4362-80CB-2977FF826DCA}.Release|x86.ActiveCfg = Release|Any CPU
{7E268085-1046-4362-80CB-2977FF826DCA}.Release|x86.Build.0 = Release|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x64.ActiveCfg = Debug|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x64.Build.0 = Debug|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x86.ActiveCfg = Debug|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x86.Build.0 = Debug|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|Any CPU.Build.0 = Release|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x64.ActiveCfg = Release|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x64.Build.0 = Release|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x86.ActiveCfg = Release|Any CPU
{A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x86.Build.0 = Release|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x64.ActiveCfg = Debug|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x64.Build.0 = Debug|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x86.ActiveCfg = Debug|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x86.Build.0 = Debug|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|Any CPU.Build.0 = Release|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x64.ActiveCfg = Release|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x64.Build.0 = Release|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x86.ActiveCfg = Release|Any CPU
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x86.Build.0 = Release|Any CPU
{9788C76F-658B-4441-88F8-22C6B86FAD27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9788C76F-658B-4441-88F8-22C6B86FAD27}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9788C76F-658B-4441-88F8-22C6B86FAD27}.Debug|x64.ActiveCfg = Debug|Any CPU
{9788C76F-658B-4441-88F8-22C6B86FAD27}.Debug|x64.Build.0 = Debug|Any CPU
{9788C76F-658B-4441-88F8-22C6B86FAD27}.Debug|x86.ActiveCfg = Debug|Any CPU
{9788C76F-658B-4441-88F8-22C6B86FAD27}.Debug|x86.Build.0 = Debug|Any CPU
{9788C76F-658B-4441-88F8-22C6B86FAD27}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9788C76F-658B-4441-88F8-22C6B86FAD27}.Release|Any CPU.Build.0 = Release|Any CPU
{9788C76F-658B-4441-88F8-22C6B86FAD27}.Release|x64.ActiveCfg = Release|Any CPU
{9788C76F-658B-4441-88F8-22C6B86FAD27}.Release|x64.Build.0 = Release|Any CPU
{9788C76F-658B-4441-88F8-22C6B86FAD27}.Release|x86.ActiveCfg = Release|Any CPU
{9788C76F-658B-4441-88F8-22C6B86FAD27}.Release|x86.Build.0 = Release|Any CPU
{1970D5CD-D9A4-4673-A297-179BB04199F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1970D5CD-D9A4-4673-A297-179BB04199F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1970D5CD-D9A4-4673-A297-179BB04199F4}.Debug|x64.ActiveCfg = Debug|Any CPU
{1970D5CD-D9A4-4673-A297-179BB04199F4}.Debug|x64.Build.0 = Debug|Any CPU
{1970D5CD-D9A4-4673-A297-179BB04199F4}.Debug|x86.ActiveCfg = Debug|Any CPU
{1970D5CD-D9A4-4673-A297-179BB04199F4}.Debug|x86.Build.0 = Debug|Any CPU
{1970D5CD-D9A4-4673-A297-179BB04199F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1970D5CD-D9A4-4673-A297-179BB04199F4}.Release|Any CPU.Build.0 = Release|Any CPU
{1970D5CD-D9A4-4673-A297-179BB04199F4}.Release|x64.ActiveCfg = Release|Any CPU
{1970D5CD-D9A4-4673-A297-179BB04199F4}.Release|x64.Build.0 = Release|Any CPU
{1970D5CD-D9A4-4673-A297-179BB04199F4}.Release|x86.ActiveCfg = Release|Any CPU
{1970D5CD-D9A4-4673-A297-179BB04199F4}.Release|x86.Build.0 = Release|Any CPU
{A40350FE-4334-4007-B1C3-6BEB1B070309}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A40350FE-4334-4007-B1C3-6BEB1B070309}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A40350FE-4334-4007-B1C3-6BEB1B070309}.Debug|x64.ActiveCfg = Debug|Any CPU
{A40350FE-4334-4007-B1C3-6BEB1B070309}.Debug|x64.Build.0 = Debug|Any CPU
{A40350FE-4334-4007-B1C3-6BEB1B070309}.Debug|x86.ActiveCfg = Debug|Any CPU
{A40350FE-4334-4007-B1C3-6BEB1B070309}.Debug|x86.Build.0 = Debug|Any CPU
{A40350FE-4334-4007-B1C3-6BEB1B070309}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A40350FE-4334-4007-B1C3-6BEB1B070309}.Release|Any CPU.Build.0 = Release|Any CPU
{A40350FE-4334-4007-B1C3-6BEB1B070309}.Release|x64.ActiveCfg = Release|Any CPU
{A40350FE-4334-4007-B1C3-6BEB1B070309}.Release|x64.Build.0 = Release|Any CPU
{A40350FE-4334-4007-B1C3-6BEB1B070309}.Release|x86.ActiveCfg = Release|Any CPU
{A40350FE-4334-4007-B1C3-6BEB1B070309}.Release|x86.Build.0 = Release|Any CPU
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Debug|x64.ActiveCfg = Debug|Any CPU
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Debug|x64.Build.0 = Debug|Any CPU
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Debug|x86.ActiveCfg = Debug|Any CPU
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Debug|x86.Build.0 = Debug|Any CPU
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Release|Any CPU.Build.0 = Release|Any CPU
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Release|x64.ActiveCfg = Release|Any CPU
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Release|x64.Build.0 = Release|Any CPU
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Release|x86.ActiveCfg = Release|Any CPU
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Release|x86.Build.0 = Release|Any CPU
{FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Debug|x64.ActiveCfg = Debug|Any CPU
{FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Debug|x64.Build.0 = Debug|Any CPU
{FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Debug|x86.ActiveCfg = Debug|Any CPU
{FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Debug|x86.Build.0 = Debug|Any CPU
{FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Release|Any CPU.Build.0 = Release|Any CPU
{FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Release|x64.ActiveCfg = Release|Any CPU
{FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Release|x64.Build.0 = Release|Any CPU
{FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Release|x86.ActiveCfg = Release|Any CPU
{FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Release|x86.Build.0 = Release|Any CPU
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Debug|x64.ActiveCfg = Debug|Any CPU
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Debug|x64.Build.0 = Debug|Any CPU
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Debug|x86.ActiveCfg = Debug|Any CPU
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Debug|x86.Build.0 = Debug|Any CPU
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Release|Any CPU.Build.0 = Release|Any CPU
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Release|x64.ActiveCfg = Release|Any CPU
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Release|x64.Build.0 = Release|Any CPU
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Release|x86.ActiveCfg = Release|Any CPU
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Release|x86.Build.0 = Release|Any CPU
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Debug|x64.ActiveCfg = Debug|Any CPU
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Debug|x64.Build.0 = Debug|Any CPU
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Debug|x86.ActiveCfg = Debug|Any CPU
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Debug|x86.Build.0 = Debug|Any CPU
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Release|Any CPU.Build.0 = Release|Any CPU
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Release|x64.ActiveCfg = Release|Any CPU
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Release|x64.Build.0 = Release|Any CPU
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Release|x86.ActiveCfg = Release|Any CPU
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Release|x86.Build.0 = Release|Any CPU
{55CACC1F-FE96-47C8-8073-91F4CAA55C75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55CACC1F-FE96-47C8-8073-91F4CAA55C75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55CACC1F-FE96-47C8-8073-91F4CAA55C75}.Debug|x64.ActiveCfg = Debug|Any CPU
{55CACC1F-FE96-47C8-8073-91F4CAA55C75}.Debug|x64.Build.0 = Debug|Any CPU
{55CACC1F-FE96-47C8-8073-91F4CAA55C75}.Debug|x86.ActiveCfg = Debug|Any CPU
{55CACC1F-FE96-47C8-8073-91F4CAA55C75}.Debug|x86.Build.0 = Debug|Any CPU
{55CACC1F-FE96-47C8-8073-91F4CAA55C75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55CACC1F-FE96-47C8-8073-91F4CAA55C75}.Release|Any CPU.Build.0 = Release|Any CPU
{55CACC1F-FE96-47C8-8073-91F4CAA55C75}.Release|x64.ActiveCfg = Release|Any CPU
{55CACC1F-FE96-47C8-8073-91F4CAA55C75}.Release|x64.Build.0 = Release|Any CPU
{55CACC1F-FE96-47C8-8073-91F4CAA55C75}.Release|x86.ActiveCfg = Release|Any CPU
{55CACC1F-FE96-47C8-8073-91F4CAA55C75}.Release|x86.Build.0 = Release|Any CPU
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Debug|x64.ActiveCfg = Debug|Any CPU
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Debug|x64.Build.0 = Debug|Any CPU
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Debug|x86.ActiveCfg = Debug|Any CPU
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Debug|x86.Build.0 = Debug|Any CPU
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Release|Any CPU.Build.0 = Release|Any CPU
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Release|x64.ActiveCfg = Release|Any CPU
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Release|x64.Build.0 = Release|Any CPU
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Release|x86.ActiveCfg = Release|Any CPU
{7509AA1E-3093-4BEE-984F-E11579E98A11}.Release|x86.Build.0 = Release|Any CPU
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|x64.ActiveCfg = Debug|Any CPU
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|x64.Build.0 = Debug|Any CPU
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|x86.ActiveCfg = Debug|Any CPU
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Debug|x86.Build.0 = Debug|Any CPU
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|Any CPU.Build.0 = Release|Any CPU
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|x64.ActiveCfg = Release|Any CPU
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|x64.Build.0 = Release|Any CPU
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|x86.ActiveCfg = Release|Any CPU
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -7771,10 +7893,8 @@ Global
{8550A02D-BA13-411A-AAD3-6124D33D669F} = {47EF1A9F-89DB-4EBA-9BC1-1D4E0E12DE44}
{EDE77D0C-321A-49FD-95D7-56ED41242A93} = {47EF1A9F-89DB-4EBA-9BC1-1D4E0E12DE44}
{8BDEC645-73BD-453B-8A5C-D616BC4EA08D} = {7B976D8F-EA31-4C0B-97BD-DFD9B3CC86FB}
{CBCD6AC2-72D3-4E82-9E78-12E3A9C68E1D} = {7B976D8F-EA31-4C0B-97BD-DFD9B3CC86FB}
{EE9D0952-6060-4723-B329-94A2950A6762} = {4FDDC525-4E60-4CAF-83A3-261C5B43721F}
{132D43A2-067A-4E24-A520-45B9F14DCB8E} = {EE9D0952-6060-4723-B329-94A2950A6762}
{FA8D7CA4-C33B-4409-865F-54192BAC59A4} = {7B976D8F-EA31-4C0B-97BD-DFD9B3CC86FB}
{2EC4E939-513F-44CD-A956-498966EAC929} = {7B976D8F-EA31-4C0B-97BD-DFD9B3CC86FB}
{987E1C29-F124-40C8-8E6F-1B2B6A4CB62A} = {4FDDC525-4E60-4CAF-83A3-261C5B43721F}
{3CBC4802-E9B8-48B7-BC8C-B0AFB9EEC643} = {0ACCEDA7-339C-4B4D-8DD4-1AC271F31C04}
@ -7788,8 +7908,6 @@ Global
{83371889-9A3E-4D16-AE77-EB4F83BC6374} = {FED4267E-E5E4-49C5-98DB-8B3F203596EE}
{525EBCB4-A870-470B-BC90-845306C337D1} = {FED4267E-E5E4-49C5-98DB-8B3F203596EE}
{175E5CD8-92D4-46BB-882E-3A930D3302D4} = {FED4267E-E5E4-49C5-98DB-8B3F203596EE}
{A5CE25E9-89E1-4F2C-9B89-0C161707E700} = {B6118E15-C37A-4B05-B4DF-97FE99790417}
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6} = {B6118E15-C37A-4B05-B4DF-97FE99790417}
{6126DCE4-9692-4EE2-B240-C65743572995} = {0508E463-0269-40C9-B5C2-3B600FB2A28B}
{46FB7E93-1294-4068-B80A-D4864F78277A} = {6126DCE4-9692-4EE2-B240-C65743572995}
{25FA84DB-EEA7-4068-8E2D-F3D48B281C16} = {6126DCE4-9692-4EE2-B240-C65743572995}
@ -7814,6 +7932,23 @@ Global
{7F87406C-A3C8-4139-A68D-E4C344294A67} = {D62AF49B-F9FE-4794-AC39-A473FF13CA81}
{1533E271-F61B-441B-8B74-59FB61DF0552} = {D62AF49B-F9FE-4794-AC39-A473FF13CA81}
{7E268085-1046-4362-80CB-2977FF826DCA} = {D62AF49B-F9FE-4794-AC39-A473FF13CA81}
{A5CE25E9-89E1-4F2C-9B89-0C161707E700} = {B6118E15-C37A-4B05-B4DF-97FE99790417}
{E6A23627-8D63-4DF1-A4F2-8881172C1FE6} = {B6118E15-C37A-4B05-B4DF-97FE99790417}
{7D2B0799-A634-42AC-AE77-5D167BA51389} = {562D5067-8CD8-4F19-BCBB-873204932C61}
{9788C76F-658B-4441-88F8-22C6B86FAD27} = {7D2B0799-A634-42AC-AE77-5D167BA51389}
{1970D5CD-D9A4-4673-A297-179BB04199F4} = {7D2B0799-A634-42AC-AE77-5D167BA51389}
{A40350FE-4334-4007-B1C3-6BEB1B070309} = {7D2B0799-A634-42AC-AE77-5D167BA51389}
{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F} = {7D2B0799-A634-42AC-AE77-5D167BA51389}
{FE5290C7-45DA-46F8-BD74-698E7A161DD6} = {7D2B0799-A634-42AC-AE77-5D167BA51389}
{ED66DC0E-FD6A-477A-BA8A-5273AA64F580} = {7D2B0799-A634-42AC-AE77-5D167BA51389}
{C1E7F837-6988-43E2-9E1C-7302DB484F99} = {017429CC-C5FB-48B4-9C46-034E29EE2F06}
{2A91479A-4ABE-4BB7-9A5E-CA3B9CCFC69E} = {C1E7F837-6988-43E2-9E1C-7302DB484F99}
{7CB09412-C9B0-47E8-A8C3-311AA4CFDE04} = {C1E7F837-6988-43E2-9E1C-7302DB484F99}
{22D7D74B-565D-4047-97B4-F149B1A13350} = {2A91479A-4ABE-4BB7-9A5E-CA3B9CCFC69E}
{B06040BC-DA28-4923-8CAC-20EB517D471B} = {22D7D74B-565D-4047-97B4-F149B1A13350}
{55CACC1F-FE96-47C8-8073-91F4CAA55C75} = {2A91479A-4ABE-4BB7-9A5E-CA3B9CCFC69E}
{7509AA1E-3093-4BEE-984F-E11579E98A11} = {7CB09412-C9B0-47E8-A8C3-311AA4CFDE04}
{DAAB6B35-CBD2-4573-B633-CDD42F583A0E} = {16898702-3E33-41C1-B8D8-4CE3F1D46BD9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F}

View File

@ -267,4 +267,29 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.
License notice for BedrockFramework
===================================
MIT License
Copyright (c) 2019 David Fowler
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -64,6 +64,7 @@ and are generated based on the last package release.
<LatestPackageReference Include="System.ComponentModel.Annotations" />
<LatestPackageReference Include="System.Diagnostics.DiagnosticSource" />
<LatestPackageReference Include="System.Diagnostics.EventLog" />
<LatestPackageReference Include="System.DirectoryServices.Protocols" />
<LatestPackageReference Include="System.Drawing.Common" />
<LatestPackageReference Include="System.IO.Pipelines" />
<LatestPackageReference Include="System.Net.Http" />
@ -107,6 +108,7 @@ and are generated based on the last package release.
<LatestPackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
<LatestPackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" />
<LatestPackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" />
<LatestPackageReference Include="Microsoft.EntityFrameworkCore.Design" />
<LatestPackageReference Include="Microsoft.EntityFrameworkCore.InMemory" />
<LatestPackageReference Include="Microsoft.EntityFrameworkCore.Relational" />
<LatestPackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />

View File

@ -13,305 +13,313 @@
<Uri>https://github.com/dotnet/blazor</Uri>
<Sha>cc449601d638ffaab58ae9487f0fd010bb178a12</Sha>
</Dependency>
<Dependency Name="dotnet-ef" Version="5.0.0-rc.1.20417.2">
<Dependency Name="dotnet-ef" Version="5.0.0-rc.1.20425.4">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha>
<Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.0-rc.1.20417.2">
<Dependency Name="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.0-rc.1.20425.4">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha>
<Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore.Relational" Version="5.0.0-rc.1.20417.2">
<Dependency Name="Microsoft.EntityFrameworkCore.Relational" Version="5.0.0-rc.1.20425.4">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha>
<Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.0-rc.1.20417.2">
<Dependency Name="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.0-rc.1.20425.4">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha>
<Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0-rc.1.20417.2">
<Dependency Name="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0-rc.1.20425.4">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha>
<Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore.Tools" Version="5.0.0-rc.1.20417.2">
<Dependency Name="Microsoft.EntityFrameworkCore.Tools" Version="5.0.0-rc.1.20425.4">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha>
<Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore" Version="5.0.0-rc.1.20417.2">
<Dependency Name="Microsoft.EntityFrameworkCore" Version="5.0.0-rc.1.20425.4">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha>
<Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0-rc.1.20416.7">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Dependency Name="Microsoft.EntityFrameworkCore.Design" Version="5.0.0-rc.1.20425.4">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Caching.Memory" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Caching.Memory" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.Binder" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.CommandLine" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Configuration.Binder" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Configuration.CommandLine" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.FileExtensions" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.Ini" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Configuration.FileExtensions" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.Json" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Configuration.Ini" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.UserSecrets" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Configuration.Json" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration.Xml" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Configuration.UserSecrets" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Configuration" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Configuration.Xml" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Configuration" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.DependencyInjection" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.FileProviders.Abstractions" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.DependencyInjection" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.FileProviders.Composite" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.FileProviders.Abstractions" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.FileProviders.Physical" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.FileProviders.Composite" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.FileSystemGlobbing" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.FileProviders.Physical" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.HostFactoryResolver.Sources" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.FileSystemGlobbing" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.HostFactoryResolver.Sources" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Hosting" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Http" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Hosting" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Http" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.Configuration" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.Console" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Logging.Configuration" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.Debug" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Logging.Console" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.EventSource" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Logging.Debug" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.EventLog" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Logging.EventSource" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging.TraceSource" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Logging.EventLog" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Logging" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Logging.TraceSource" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Logging" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Options.DataAnnotations" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Options" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Options.DataAnnotations" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Primitives" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Options" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Internal.Transport" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Primitives" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Win32.Registry" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.Internal.Transport" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Win32.SystemEvents" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Win32.Registry" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.ComponentModel.Annotations" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Win32.SystemEvents" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Diagnostics.DiagnosticSource" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.ComponentModel.Annotations" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Diagnostics.EventLog" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Diagnostics.DiagnosticSource" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Drawing.Common" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Diagnostics.EventLog" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.IO.Pipelines" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.DirectoryServices.Protocols" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Net.Http.Json" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Drawing.Common" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Net.Http.WinHttpHandler" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.IO.Pipelines" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Net.WebSockets.WebSocketProtocol" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Net.Http.Json" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Reflection.Metadata" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Net.Http.WinHttpHandler" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Resources.Extensions" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Net.WebSockets.WebSocketProtocol" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Runtime.CompilerServices.Unsafe" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Reflection.Metadata" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Resources.Extensions" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Runtime.CompilerServices.Unsafe" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<!-- System.Security.AccessControl should only be referenced in Dependencies.props and RTMVersions.csproj. -->
<Dependency Name="System.Security.AccessControl" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Security.AccessControl" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Security.Cryptography.Cng" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Security.Cryptography.Cng" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Security.Cryptography.Pkcs" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Security.Cryptography.Pkcs" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Security.Cryptography.Xml" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Security.Cryptography.Xml" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Security.Permissions" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Security.Permissions" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Security.Principal.Windows" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Security.Principal.Windows" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.ServiceProcess.ServiceController" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.ServiceProcess.ServiceController" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Text.Encodings.Web" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Text.Encodings.Web" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Text.Json" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Text.Json" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Threading.Channels" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Threading.Channels" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="System.Windows.Extensions" Version="5.0.0-rc.1.20416.7">
<Dependency Name="System.Windows.Extensions" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.DependencyModel" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.Extensions.DependencyModel" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.NETCore.App.Ref" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.NETCore.App.Ref" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<!--
Win-x64 is used here because we have picked an arbitrary runtime identifier to flow the version of the latest NETCore.App runtime.
All Runtime.$rid packages should have the same version.
-->
<Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.NETCore.App.Internal" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.NETCore.App.Internal" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
</ProductDependencies>
<ToolsetDependencies>
<!-- Listed explicitly to workaround https://github.com/dotnet/cli/issues/10528 -->
<Dependency Name="Microsoft.NETCore.Platforms" Version="5.0.0-rc.1.20416.7">
<Dependency Name="Microsoft.NETCore.Platforms" Version="5.0.0-rc.1.20425.1">
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha>
<Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="5.0.0-beta.20411.8">
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="5.0.0-beta.20419.21">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>ecec08a0eebbd92bb9538e351d475582551d9092</Sha>
<Sha>56a95cc477558c1ccdf16d7abe962849ea970ba4</Sha>
</Dependency>
<Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="5.0.0-beta.20411.8">
<Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="5.0.0-beta.20419.21">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>ecec08a0eebbd92bb9538e351d475582551d9092</Sha>
<Sha>56a95cc477558c1ccdf16d7abe962849ea970ba4</Sha>
</Dependency>
<Dependency Name="Microsoft.Net.Compilers.Toolset" Version="3.8.0-2.20407.3">
<Uri>https://github.com/dotnet/roslyn</Uri>

View File

@ -64,82 +64,84 @@
<!-- Packages from dotnet/roslyn -->
<MicrosoftNetCompilersToolsetPackageVersion>3.8.0-2.20407.3</MicrosoftNetCompilersToolsetPackageVersion>
<!-- Packages from dotnet/runtime -->
<MicrosoftExtensionsDependencyModelPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsDependencyModelPackageVersion>
<MicrosoftNETCoreAppInternalPackageVersion>5.0.0-rc.1.20416.7</MicrosoftNETCoreAppInternalPackageVersion>
<MicrosoftNETCoreAppRefPackageVersion>5.0.0-rc.1.20416.7</MicrosoftNETCoreAppRefPackageVersion>
<MicrosoftNETCoreAppRuntimewinx64PackageVersion>5.0.0-rc.1.20416.7</MicrosoftNETCoreAppRuntimewinx64PackageVersion>
<MicrosoftWin32RegistryPackageVersion>5.0.0-rc.1.20416.7</MicrosoftWin32RegistryPackageVersion>
<MicrosoftWin32SystemEventsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftWin32SystemEventsPackageVersion>
<MicrosoftExtensionsCachingAbstractionsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsCachingAbstractionsPackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsConfigurationAbstractionsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsConfigurationAbstractionsPackageVersion>
<MicrosoftExtensionsConfigurationBinderPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsConfigurationBinderPackageVersion>
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
<MicrosoftExtensionsConfigurationFileExtensionsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsConfigurationFileExtensionsPackageVersion>
<MicrosoftExtensionsConfigurationIniPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsConfigurationIniPackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsConfigurationPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsConfigurationPackageVersion>
<MicrosoftExtensionsConfigurationUserSecretsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsConfigurationUserSecretsPackageVersion>
<MicrosoftExtensionsConfigurationXmlPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsConfigurationXmlPackageVersion>
<MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
<MicrosoftExtensionsFileProvidersCompositePackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsFileProvidersCompositePackageVersion>
<MicrosoftExtensionsFileProvidersPhysicalPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsFileProvidersPhysicalPackageVersion>
<MicrosoftExtensionsFileSystemGlobbingPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsFileSystemGlobbingPackageVersion>
<MicrosoftExtensionsHostFactoryResolverSourcesPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsHostFactoryResolverSourcesPackageVersion>
<MicrosoftExtensionsHostingAbstractionsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsHostingAbstractionsPackageVersion>
<MicrosoftExtensionsHostingPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsHostingPackageVersion>
<MicrosoftExtensionsHttpPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsHttpPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConfigurationPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsLoggingConfigurationPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingEventSourcePackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsLoggingEventSourcePackageVersion>
<MicrosoftExtensionsLoggingEventLogPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsLoggingEventLogPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTraceSourcePackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsLoggingTraceSourcePackageVersion>
<MicrosoftExtensionsOptionsConfigurationExtensionsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsOptionsConfigurationExtensionsPackageVersion>
<MicrosoftExtensionsOptionsDataAnnotationsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsOptionsDataAnnotationsPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsPrimitivesPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsPrimitivesPackageVersion>
<MicrosoftExtensionsInternalTransportPackageVersion>5.0.0-rc.1.20416.7</MicrosoftExtensionsInternalTransportPackageVersion>
<SystemComponentModelAnnotationsPackageVersion>5.0.0-rc.1.20416.7</SystemComponentModelAnnotationsPackageVersion>
<SystemDiagnosticsDiagnosticSourcePackageVersion>5.0.0-rc.1.20416.7</SystemDiagnosticsDiagnosticSourcePackageVersion>
<SystemDiagnosticsEventLogPackageVersion>5.0.0-rc.1.20416.7</SystemDiagnosticsEventLogPackageVersion>
<SystemDrawingCommonPackageVersion>5.0.0-rc.1.20416.7</SystemDrawingCommonPackageVersion>
<SystemIOPipelinesPackageVersion>5.0.0-rc.1.20416.7</SystemIOPipelinesPackageVersion>
<SystemNetHttpJsonPackageVersion>5.0.0-rc.1.20416.7</SystemNetHttpJsonPackageVersion>
<SystemNetHttpWinHttpHandlerPackageVersion>5.0.0-rc.1.20416.7</SystemNetHttpWinHttpHandlerPackageVersion>
<SystemNetWebSocketsWebSocketProtocolPackageVersion>5.0.0-rc.1.20416.7</SystemNetWebSocketsWebSocketProtocolPackageVersion>
<SystemReflectionMetadataPackageVersion>5.0.0-rc.1.20416.7</SystemReflectionMetadataPackageVersion>
<SystemResourcesExtensionsPackageVersion>5.0.0-rc.1.20416.7</SystemResourcesExtensionsPackageVersion>
<SystemRuntimeCompilerServicesUnsafePackageVersion>5.0.0-rc.1.20416.7</SystemRuntimeCompilerServicesUnsafePackageVersion>
<MicrosoftExtensionsDependencyModelPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsDependencyModelPackageVersion>
<MicrosoftNETCoreAppInternalPackageVersion>5.0.0-rc.1.20425.1</MicrosoftNETCoreAppInternalPackageVersion>
<MicrosoftNETCoreAppRefPackageVersion>5.0.0-rc.1.20425.1</MicrosoftNETCoreAppRefPackageVersion>
<MicrosoftNETCoreAppRuntimewinx64PackageVersion>5.0.0-rc.1.20425.1</MicrosoftNETCoreAppRuntimewinx64PackageVersion>
<MicrosoftWin32RegistryPackageVersion>5.0.0-rc.1.20425.1</MicrosoftWin32RegistryPackageVersion>
<MicrosoftWin32SystemEventsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftWin32SystemEventsPackageVersion>
<MicrosoftExtensionsCachingAbstractionsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsCachingAbstractionsPackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsConfigurationAbstractionsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsConfigurationAbstractionsPackageVersion>
<MicrosoftExtensionsConfigurationBinderPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsConfigurationBinderPackageVersion>
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
<MicrosoftExtensionsConfigurationFileExtensionsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsConfigurationFileExtensionsPackageVersion>
<MicrosoftExtensionsConfigurationIniPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsConfigurationIniPackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsConfigurationPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsConfigurationPackageVersion>
<MicrosoftExtensionsConfigurationUserSecretsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsConfigurationUserSecretsPackageVersion>
<MicrosoftExtensionsConfigurationXmlPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsConfigurationXmlPackageVersion>
<MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
<MicrosoftExtensionsFileProvidersCompositePackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsFileProvidersCompositePackageVersion>
<MicrosoftExtensionsFileProvidersPhysicalPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsFileProvidersPhysicalPackageVersion>
<MicrosoftExtensionsFileSystemGlobbingPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsFileSystemGlobbingPackageVersion>
<MicrosoftExtensionsHostFactoryResolverSourcesPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsHostFactoryResolverSourcesPackageVersion>
<MicrosoftExtensionsHostingAbstractionsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsHostingAbstractionsPackageVersion>
<MicrosoftExtensionsHostingPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsHostingPackageVersion>
<MicrosoftExtensionsHttpPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsHttpPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConfigurationPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsLoggingConfigurationPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingEventSourcePackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsLoggingEventSourcePackageVersion>
<MicrosoftExtensionsLoggingEventLogPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsLoggingEventLogPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTraceSourcePackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsLoggingTraceSourcePackageVersion>
<MicrosoftExtensionsOptionsConfigurationExtensionsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsOptionsConfigurationExtensionsPackageVersion>
<MicrosoftExtensionsOptionsDataAnnotationsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsOptionsDataAnnotationsPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsPrimitivesPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsPrimitivesPackageVersion>
<MicrosoftExtensionsInternalTransportPackageVersion>5.0.0-rc.1.20425.1</MicrosoftExtensionsInternalTransportPackageVersion>
<SystemComponentModelAnnotationsPackageVersion>5.0.0-rc.1.20425.1</SystemComponentModelAnnotationsPackageVersion>
<SystemDiagnosticsDiagnosticSourcePackageVersion>5.0.0-rc.1.20425.1</SystemDiagnosticsDiagnosticSourcePackageVersion>
<SystemDiagnosticsEventLogPackageVersion>5.0.0-rc.1.20425.1</SystemDiagnosticsEventLogPackageVersion>
<SystemDirectoryServicesProtocolsPackageVersion>5.0.0-rc.1.20425.1</SystemDirectoryServicesProtocolsPackageVersion>
<SystemDrawingCommonPackageVersion>5.0.0-rc.1.20425.1</SystemDrawingCommonPackageVersion>
<SystemIOPipelinesPackageVersion>5.0.0-rc.1.20425.1</SystemIOPipelinesPackageVersion>
<SystemNetHttpJsonPackageVersion>5.0.0-rc.1.20425.1</SystemNetHttpJsonPackageVersion>
<SystemNetHttpWinHttpHandlerPackageVersion>5.0.0-rc.1.20425.1</SystemNetHttpWinHttpHandlerPackageVersion>
<SystemNetWebSocketsWebSocketProtocolPackageVersion>5.0.0-rc.1.20425.1</SystemNetWebSocketsWebSocketProtocolPackageVersion>
<SystemReflectionMetadataPackageVersion>5.0.0-rc.1.20425.1</SystemReflectionMetadataPackageVersion>
<SystemResourcesExtensionsPackageVersion>5.0.0-rc.1.20425.1</SystemResourcesExtensionsPackageVersion>
<SystemRuntimeCompilerServicesUnsafePackageVersion>5.0.0-rc.1.20425.1</SystemRuntimeCompilerServicesUnsafePackageVersion>
<!-- System.Security.AccessControl should only be referenced in Dependencies.props and RTMVersions.csproj. -->
<SystemSecurityAccessControlPackageVersion>5.0.0-rc.1.20416.7</SystemSecurityAccessControlPackageVersion>
<SystemSecurityCryptographyCngPackageVersion>5.0.0-rc.1.20416.7</SystemSecurityCryptographyCngPackageVersion>
<SystemSecurityCryptographyPkcsPackageVersion>5.0.0-rc.1.20416.7</SystemSecurityCryptographyPkcsPackageVersion>
<SystemSecurityCryptographyXmlPackageVersion>5.0.0-rc.1.20416.7</SystemSecurityCryptographyXmlPackageVersion>
<SystemSecurityPermissionsPackageVersion>5.0.0-rc.1.20416.7</SystemSecurityPermissionsPackageVersion>
<SystemSecurityPrincipalWindowsPackageVersion>5.0.0-rc.1.20416.7</SystemSecurityPrincipalWindowsPackageVersion>
<SystemServiceProcessServiceControllerPackageVersion>5.0.0-rc.1.20416.7</SystemServiceProcessServiceControllerPackageVersion>
<SystemTextEncodingsWebPackageVersion>5.0.0-rc.1.20416.7</SystemTextEncodingsWebPackageVersion>
<SystemTextJsonPackageVersion>5.0.0-rc.1.20416.7</SystemTextJsonPackageVersion>
<SystemThreadingChannelsPackageVersion>5.0.0-rc.1.20416.7</SystemThreadingChannelsPackageVersion>
<SystemWindowsExtensionsPackageVersion>5.0.0-rc.1.20416.7</SystemWindowsExtensionsPackageVersion>
<SystemSecurityAccessControlPackageVersion>5.0.0-rc.1.20425.1</SystemSecurityAccessControlPackageVersion>
<SystemSecurityCryptographyCngPackageVersion>5.0.0-rc.1.20425.1</SystemSecurityCryptographyCngPackageVersion>
<SystemSecurityCryptographyPkcsPackageVersion>5.0.0-rc.1.20425.1</SystemSecurityCryptographyPkcsPackageVersion>
<SystemSecurityCryptographyXmlPackageVersion>5.0.0-rc.1.20425.1</SystemSecurityCryptographyXmlPackageVersion>
<SystemSecurityPermissionsPackageVersion>5.0.0-rc.1.20425.1</SystemSecurityPermissionsPackageVersion>
<SystemSecurityPrincipalWindowsPackageVersion>5.0.0-rc.1.20425.1</SystemSecurityPrincipalWindowsPackageVersion>
<SystemServiceProcessServiceControllerPackageVersion>5.0.0-rc.1.20425.1</SystemServiceProcessServiceControllerPackageVersion>
<SystemTextEncodingsWebPackageVersion>5.0.0-rc.1.20425.1</SystemTextEncodingsWebPackageVersion>
<SystemTextJsonPackageVersion>5.0.0-rc.1.20425.1</SystemTextJsonPackageVersion>
<SystemThreadingChannelsPackageVersion>5.0.0-rc.1.20425.1</SystemThreadingChannelsPackageVersion>
<SystemWindowsExtensionsPackageVersion>5.0.0-rc.1.20425.1</SystemWindowsExtensionsPackageVersion>
<!-- Only listed explicitly to workaround https://github.com/dotnet/cli/issues/10528 -->
<MicrosoftNETCorePlatformsPackageVersion>5.0.0-rc.1.20416.7</MicrosoftNETCorePlatformsPackageVersion>
<MicrosoftNETCorePlatformsPackageVersion>5.0.0-rc.1.20425.1</MicrosoftNETCorePlatformsPackageVersion>
<!-- Packages from dotnet/blazor -->
<MicrosoftAspNetCoreComponentsWebAssemblyRuntimePackageVersion>3.2.0</MicrosoftAspNetCoreComponentsWebAssemblyRuntimePackageVersion>
<!-- Packages from dotnet/efcore -->
<dotnetefPackageVersion>5.0.0-rc.1.20417.2</dotnetefPackageVersion>
<MicrosoftEntityFrameworkCoreInMemoryPackageVersion>5.0.0-rc.1.20417.2</MicrosoftEntityFrameworkCoreInMemoryPackageVersion>
<MicrosoftEntityFrameworkCoreRelationalPackageVersion>5.0.0-rc.1.20417.2</MicrosoftEntityFrameworkCoreRelationalPackageVersion>
<MicrosoftEntityFrameworkCoreSqlitePackageVersion>5.0.0-rc.1.20417.2</MicrosoftEntityFrameworkCoreSqlitePackageVersion>
<MicrosoftEntityFrameworkCoreSqlServerPackageVersion>5.0.0-rc.1.20417.2</MicrosoftEntityFrameworkCoreSqlServerPackageVersion>
<MicrosoftEntityFrameworkCoreToolsPackageVersion>5.0.0-rc.1.20417.2</MicrosoftEntityFrameworkCoreToolsPackageVersion>
<MicrosoftEntityFrameworkCorePackageVersion>5.0.0-rc.1.20417.2</MicrosoftEntityFrameworkCorePackageVersion>
<dotnetefPackageVersion>5.0.0-rc.1.20425.4</dotnetefPackageVersion>
<MicrosoftEntityFrameworkCoreInMemoryPackageVersion>5.0.0-rc.1.20425.4</MicrosoftEntityFrameworkCoreInMemoryPackageVersion>
<MicrosoftEntityFrameworkCoreRelationalPackageVersion>5.0.0-rc.1.20425.4</MicrosoftEntityFrameworkCoreRelationalPackageVersion>
<MicrosoftEntityFrameworkCoreSqlitePackageVersion>5.0.0-rc.1.20425.4</MicrosoftEntityFrameworkCoreSqlitePackageVersion>
<MicrosoftEntityFrameworkCoreSqlServerPackageVersion>5.0.0-rc.1.20425.4</MicrosoftEntityFrameworkCoreSqlServerPackageVersion>
<MicrosoftEntityFrameworkCoreToolsPackageVersion>5.0.0-rc.1.20425.4</MicrosoftEntityFrameworkCoreToolsPackageVersion>
<MicrosoftEntityFrameworkCorePackageVersion>5.0.0-rc.1.20425.4</MicrosoftEntityFrameworkCorePackageVersion>
<MicrosoftEntityFrameworkCoreDesignPackageVersion>5.0.0-rc.1.20425.4</MicrosoftEntityFrameworkCoreDesignPackageVersion>
</PropertyGroup>
<!--
@ -250,11 +252,11 @@
<GrpcAuthPackageVersion>2.27.0</GrpcAuthPackageVersion>
<GrpcNetClientPackageVersion>2.27.0</GrpcNetClientPackageVersion>
<GrpcToolsPackageVersion>2.27.0</GrpcToolsPackageVersion>
<IdentityServer4AspNetIdentityPackageVersion>3.0.0</IdentityServer4AspNetIdentityPackageVersion>
<IdentityServer4EntityFrameworkPackageVersion>3.0.0</IdentityServer4EntityFrameworkPackageVersion>
<IdentityServer4PackageVersion>3.0.0</IdentityServer4PackageVersion>
<IdentityServer4StoragePackageVersion>3.0.0</IdentityServer4StoragePackageVersion>
<IdentityServer4EntityFrameworkStoragePackageVersion>3.0.0</IdentityServer4EntityFrameworkStoragePackageVersion>
<IdentityServer4AspNetIdentityPackageVersion>4.0.4</IdentityServer4AspNetIdentityPackageVersion>
<IdentityServer4EntityFrameworkPackageVersion>4.0.4</IdentityServer4EntityFrameworkPackageVersion>
<IdentityServer4PackageVersion>4.0.4</IdentityServer4PackageVersion>
<IdentityServer4StoragePackageVersion>4.0.4</IdentityServer4StoragePackageVersion>
<IdentityServer4EntityFrameworkStoragePackageVersion>4.0.4</IdentityServer4EntityFrameworkStoragePackageVersion>
<MessagePackPackageVersion>2.1.90</MessagePackPackageVersion>
<MicrosoftIdentityWebPackageVersion>0.2.1-preview</MicrosoftIdentityWebPackageVersion>
<MicrosoftIdentityWebUIPackageVersion>0.2.1-preview</MicrosoftIdentityWebUIPackageVersion>
@ -273,6 +275,7 @@
<SerilogSinksFilePackageVersion>4.0.0</SerilogSinksFilePackageVersion>
<StackExchangeRedisPackageVersion>2.0.593</StackExchangeRedisPackageVersion>
<SystemReactiveLinqPackageVersion>3.1.1</SystemReactiveLinqPackageVersion>
<SwashbuckleAspNetCorePackageVersion>5.5.1</SwashbuckleAspNetCorePackageVersion>
<XunitAbstractionsPackageVersion>2.0.3</XunitAbstractionsPackageVersion>
<XunitAnalyzersPackageVersion>0.10.0</XunitAnalyzersPackageVersion>
<XunitVersion>2.4.1</XunitVersion>

View File

@ -19,7 +19,9 @@ if(TARGET_ARCH_NAME STREQUAL "armel")
endif()
elseif(TARGET_ARCH_NAME STREQUAL "arm")
set(CMAKE_SYSTEM_PROCESSOR armv7l)
if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf)
if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv7-alpine-linux-musleabihf)
set(TOOLCHAIN "armv7-alpine-linux-musleabihf")
elseif(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf)
set(TOOLCHAIN "armv6-alpine-linux-musleabihf")
else()
set(TOOLCHAIN "arm-linux-gnueabihf")

View File

@ -199,14 +199,15 @@ if [[ "$mono_dotnet" != "" ]]; then
fi
if [[ "$wasm_runtime_loc" != "" ]]; then
configurations="CompilationMode=wasm;RunKind=micro"
configurations="CompilationMode=wasm RunKind=micro"
extra_benchmark_dotnet_arguments="$extra_benchmark_dotnet_arguments --category-exclusion-filter NoInterpreter NoWASM"
fi
if [[ "$monointerpreter" == "true" ]]; then
extra_benchmark_dotnet_arguments="$extra_benchmark_dotnet_arguments --category-exclusion-filter NoInterpreter"
fi
common_setup_arguments="--channel master --queue $queue --build-number $build_number --build-configs \"$configurations\" --architecture $architecture"
common_setup_arguments="--channel master --queue $queue --build-number $build_number --build-configs $configurations --architecture $architecture"
setup_arguments="--repository https://github.com/$repository --branch $branch --get-perf-hash --commit-sha $commit_sha $common_setup_arguments"

View File

@ -1,12 +1,13 @@
param(
[Parameter(Mandatory=$true)][int] $BuildId,
[Parameter(Mandatory=$true)][int] $PublishingInfraVersion,
[Parameter(Mandatory=$true)][string] $AzdoToken,
[Parameter(Mandatory=$true)][string] $MaestroToken,
[Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro-prod.westus2.cloudapp.azure.com',
[Parameter(Mandatory=$true)][string] $WaitPublishingFinish,
[Parameter(Mandatory=$true)][string] $EnableSourceLinkValidation,
[Parameter(Mandatory=$true)][string] $EnableSigningValidation,
[Parameter(Mandatory=$true)][string] $EnableNugetValidation,
[Parameter(Mandatory=$false)][string] $EnableSourceLinkValidation,
[Parameter(Mandatory=$false)][string] $EnableSigningValidation,
[Parameter(Mandatory=$false)][string] $EnableNugetValidation,
[Parameter(Mandatory=$true)][string] $PublishInstallersAndChecksums,
[Parameter(Mandatory=$false)][string] $ArtifactsPublishingAdditionalParameters,
[Parameter(Mandatory=$false)][string] $SigningValidationAdditionalParameters
@ -14,7 +15,8 @@ param(
try {
. $PSScriptRoot\post-build-utils.ps1
. $PSScriptRoot\..\darc-init.ps1
# Hard coding darc version till the next arcade-services roll out, cos this version has required API changes for darc add-build-to-channel
. $PSScriptRoot\..\darc-init.ps1 -darcVersion "1.1.0-beta.20418.1"
$optionalParams = [System.Collections.ArrayList]::new()
@ -49,12 +51,13 @@ try {
}
& darc add-build-to-channel `
--id $buildId `
--default-channels `
--source-branch master `
--azdev-pat $AzdoToken `
--bar-uri $MaestroApiEndPoint `
--password $MaestroToken `
--id $buildId `
--publishing-infra-version $PublishingInfraVersion `
--default-channels `
--source-branch master `
--azdev-pat $AzdoToken `
--bar-uri $MaestroApiEndPoint `
--password $MaestroToken `
@optionalParams
if ($LastExitCode -ne 0) {

View File

@ -1,4 +1,6 @@
parameters:
BARBuildId: ''
PromoteToChannelIds: ''
artifactsPublishingAdditionalParameters: ''
dependsOn:
- Validate
@ -19,6 +21,9 @@ stages:
displayName: ${{ parameters.channelName }} Publishing
jobs:
- template: ../setup-maestro-vars.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
- job: publish_symbols
displayName: Symbol Publishing
@ -138,6 +143,7 @@ stages:
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
/p:PublishingInfraVersion=2
/p:IsStableBuild=$(IsStableBuild)
/p:IsInternalBuild=$(IsInternalBuild)
/p:RepositoryName=$(Build.Repository.Name)

View File

@ -1,4 +1,6 @@
parameters:
BARBuildId: ''
PromoteToChannelIds: ''
artifactsPublishingAdditionalParameters: ''
dependsOn:
- Validate
@ -21,6 +23,9 @@ stages:
displayName: ${{ parameters.channelName }} Publishing
jobs:
- template: ../setup-maestro-vars.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
- job: publish_symbols
displayName: Symbol Publishing
@ -137,6 +142,7 @@ stages:
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
/p:PublishingInfraVersion=2
/p:ArtifactsCategory=$(ArtifactsCategory)
/p:IsStableBuild=$(IsStableBuild)
/p:IsInternalBuild=$(IsInternalBuild)

View File

@ -1,13 +1,20 @@
parameters:
# Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST.
# Publishing V2 accepts optionally outlining the publishing stages - default is inline.
# Publishing V3 DOES NOT accept inlining the publishing stages.
publishingInfraVersion: 2
# When set to true the publishing templates from the repo will be used
# otherwise Darc add-build-to-channel will be used to trigger the promotion pipeline
inline: true
# Only used if inline==false. When set to true will stall the current build until
# the Promotion Pipeline build finishes. Otherwise, the current build continue
# the Promotion Pipeline build finishes. Otherwise, the current build will continue
# execution concurrently with the promotion build.
waitPublishingFinish: true
BARBuildId: ''
PromoteToChannelIds: ''
enableSourceLinkValidation: false
enableSigningValidation: true
enableSymbolValidation: false
@ -39,6 +46,7 @@ parameters:
NetEngLatestChannelId: 2
NetEngValidationChannelId: 9
NetDev5ChannelId: 131
NetDev6ChannelId: 1296
GeneralTestingChannelId: 529
NETCoreToolingDevChannelId: 548
NETCoreToolingReleaseChannelId: 549
@ -46,7 +54,6 @@ parameters:
NETCoreExperimentalChannelId: 562
NetEngServicesIntChannelId: 678
NetEngServicesProdChannelId: 679
Net5Preview7ChannelId: 1065
Net5Preview8ChannelId: 1155
Net5RC1ChannelId: 1157
NetCoreSDK313xxChannelId: 759
@ -59,14 +66,183 @@ parameters:
VSMasterChannelId: 1012
stages:
- ${{ if ne(parameters.inline, 'true') }}:
- stage: Validate
dependsOn: ${{ parameters.validateDependsOn }}
displayName: Validate Build Assets
variables:
- template: common-variables.yml
jobs:
- template: setup-maestro-vars.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
- job:
displayName: Post-build Checks
dependsOn: setupMaestroVars
variables:
- name: TargetChannels
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'] ]
pool:
vmImage: 'windows-2019'
steps:
- task: PowerShell@2
displayName: Maestro Channels Consistency
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/check-channel-consistency.ps1
arguments: -PromoteToChannels "$(TargetChannels)"
-AvailableChannelIds ${{parameters.NetEngLatestChannelId}},${{parameters.NetEngValidationChannelId}},${{parameters.NetDev5ChannelId}},${{parameters.NetDev6ChannelId}},${{parameters.GeneralTestingChannelId}},${{parameters.NETCoreToolingDevChannelId}},${{parameters.NETCoreToolingReleaseChannelId}},${{parameters.NETInternalToolingChannelId}},${{parameters.NETCoreExperimentalChannelId}},${{parameters.NetEngServicesIntChannelId}},${{parameters.NetEngServicesProdChannelId}},${{parameters.Net5Preview8ChannelId}},${{parameters.Net5RC1ChannelId}},${{parameters.NetCoreSDK313xxChannelId}},${{parameters.NetCoreSDK313xxInternalChannelId}},${{parameters.NetCoreSDK314xxChannelId}},${{parameters.NetCoreSDK314xxInternalChannelId}},${{parameters.VS166ChannelId}},${{parameters.VS167ChannelId}},${{parameters.VS168ChannelId}},${{parameters.VSMasterChannelId}}
- job:
displayName: NuGet Validation
dependsOn: setupMaestroVars
condition: eq( ${{ parameters.enableNugetValidation }}, 'true')
pool:
vmImage: 'windows-2019'
variables:
- name: AzDOProjectName
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
- name: AzDOPipelineId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
- name: AzDOBuildId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
steps:
- task: DownloadBuildArtifacts@0
displayName: Download Package Artifacts
inputs:
buildType: specific
buildVersionToDownload: specific
project: $(AzDOProjectName)
pipeline: $(AzDOPipelineId)
buildId: $(AzDOBuildId)
artifactName: PackageArtifacts
- task: PowerShell@2
displayName: Validate
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1
arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/
-ToolDestinationPath $(Agent.BuildDirectory)/Extract/
- job:
displayName: Signing Validation
dependsOn: setupMaestroVars
condition: eq( ${{ parameters.enableSigningValidation }}, 'true')
variables:
- template: common-variables.yml
- name: AzDOProjectName
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
- name: AzDOPipelineId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
- name: AzDOBuildId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
pool:
vmImage: 'windows-2019'
steps:
- ${{ if eq(parameters.useBuildManifest, true) }}:
- task: DownloadBuildArtifacts@0
displayName: Download build manifest
inputs:
buildType: specific
buildVersionToDownload: specific
project: $(AzDOProjectName)
pipeline: $(AzDOPipelineId)
buildId: $(AzDOBuildId)
artifactName: BuildManifests
- task: DownloadBuildArtifacts@0
displayName: Download Package Artifacts
inputs:
buildType: specific
buildVersionToDownload: specific
project: $(AzDOProjectName)
pipeline: $(AzDOPipelineId)
buildId: $(AzDOBuildId)
artifactName: PackageArtifacts
# This is necessary whenever we want to publish/restore to an AzDO private feed
# Since sdk-task.ps1 tries to restore packages we need to do this authentication here
# otherwise it'll complain about accessing a private feed.
- task: NuGetAuthenticate@0
displayName: 'Authenticate to AzDO Feeds'
- task: PowerShell@2
displayName: Enable cross-org publishing
inputs:
filePath: eng\common\enable-cross-org-publishing.ps1
arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
# Signing validation will optionally work with the buildmanifest file which is downloaded from
# Azure DevOps above.
- task: PowerShell@2
displayName: Validate
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task SigningValidation -restore -msbuildEngine vs
/p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts'
/p:SignCheckExclusionsFile='$(Build.SourcesDirectory)/eng/SignCheckExclusionsFile.txt'
${{ parameters.signingValidationAdditionalParameters }}
- template: ../steps/publish-logs.yml
parameters:
StageLabel: 'Validation'
JobLabel: 'Signing'
- job:
displayName: SourceLink Validation
dependsOn: setupMaestroVars
condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true')
variables:
- template: common-variables.yml
- name: AzDOProjectName
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
- name: AzDOPipelineId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
- name: AzDOBuildId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
pool:
vmImage: 'windows-2019'
steps:
- task: DownloadBuildArtifacts@0
displayName: Download Blob Artifacts
inputs:
buildType: specific
buildVersionToDownload: specific
project: $(AzDOProjectName)
pipeline: $(AzDOPipelineId)
buildId: $(AzDOBuildId)
artifactName: BlobArtifacts
- task: PowerShell@2
displayName: Validate
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1
arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/
-ExtractPath $(Agent.BuildDirectory)/Extract/
-GHRepoName $(Build.Repository.Name)
-GHCommit $(Build.SourceVersion)
-SourcelinkCliVersion $(SourceLinkCLIVersion)
continueOnError: true
- template: /eng/common/templates/job/execute-sdl.yml
parameters:
enable: ${{ parameters.SDLValidationParameters.enable }}
dependsOn: setupMaestroVars
additionalParameters: ${{ parameters.SDLValidationParameters.params }}
continueOnError: ${{ parameters.SDLValidationParameters.continueOnError }}
artifactNames: ${{ parameters.SDLValidationParameters.artifactNames }}
downloadArtifacts: ${{ parameters.SDLValidationParameters.downloadArtifacts }}
- ${{ if or(ge(parameters.publishingInfraVersion, 3), eq(parameters.inline, 'false')) }}:
- stage: publish_using_darc
dependsOn: ${{ parameters.validateDependsOn }}
dependsOn: Validate
displayName: Publish using Darc
variables:
- template: common-variables.yml
jobs:
- template: setup-maestro-vars.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
- job:
displayName: Publish Using Darc
@ -82,182 +258,17 @@ stages:
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
arguments: -BuildId $(BARBuildId)
-PublishingInfraVersion ${{ parameters.PublishingInfraVersion }}
-AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
-MaestroToken '$(MaestroApiAccessToken)'
-WaitPublishingFinish ${{ parameters.waitPublishingFinish }}
-EnableSourceLinkValidation ${{ parameters.enableSourceLinkValidation }}
-EnableSigningValidation ${{ parameters.enableSourceLinkValidation }}
-EnableNugetValidation ${{ parameters.enableSourceLinkValidation }}
-PublishInstallersAndChecksums ${{ parameters.publishInstallersAndChecksums }}
-ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
-SigningValidationAdditionalParameters '${{ parameters.signingValidationAdditionalParameters }}'
- ${{ if eq(parameters.inline, 'true') }}:
- stage: Validate
dependsOn: ${{ parameters.validateDependsOn }}
displayName: Validate Build Assets
variables:
- template: common-variables.yml
jobs:
- template: setup-maestro-vars.yml
- job:
displayName: Post-build Checks
dependsOn: setupMaestroVars
variables:
- name: TargetChannels
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'] ]
pool:
vmImage: 'windows-2019'
steps:
- task: PowerShell@2
displayName: Maestro Channels Consistency
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/check-channel-consistency.ps1
arguments: -PromoteToChannels "$(TargetChannels)"
-AvailableChannelIds ${{parameters.NetEngLatestChannelId}},${{parameters.NetEngValidationChannelId}},${{parameters.NetDev5ChannelId}},${{parameters.GeneralTestingChannelId}},${{parameters.NETCoreToolingDevChannelId}},${{parameters.NETCoreToolingReleaseChannelId}},${{parameters.NETInternalToolingChannelId}},${{parameters.NETCoreExperimentalChannelId}},${{parameters.NetEngServicesIntChannelId}},${{parameters.NetEngServicesProdChannelId}},${{parameters.Net5Preview7ChannelId}},${{parameters.Net5Preview8ChannelId}},${{parameters.Net5RC1ChannelId}},${{parameters.NetCoreSDK313xxChannelId}},${{parameters.NetCoreSDK313xxInternalChannelId}},${{parameters.NetCoreSDK314xxChannelId}},${{parameters.NetCoreSDK314xxInternalChannelId}},${{parameters.VS166ChannelId}},${{parameters.VS167ChannelId}},${{parameters.VS168ChannelId}},${{parameters.VSMasterChannelId}}
- job:
displayName: NuGet Validation
dependsOn: setupMaestroVars
condition: eq( ${{ parameters.enableNugetValidation }}, 'true')
pool:
vmImage: 'windows-2019'
variables:
- name: AzDOProjectName
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
- name: AzDOPipelineId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
- name: AzDOBuildId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
steps:
- task: DownloadBuildArtifacts@0
displayName: Download Package Artifacts
inputs:
buildType: specific
buildVersionToDownload: specific
project: $(AzDOProjectName)
pipeline: $(AzDOPipelineId)
buildId: $(AzDOBuildId)
artifactName: PackageArtifacts
- task: PowerShell@2
displayName: Validate
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1
arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/
-ToolDestinationPath $(Agent.BuildDirectory)/Extract/
- job:
displayName: Signing Validation
dependsOn: setupMaestroVars
condition: eq( ${{ parameters.enableSigningValidation }}, 'true')
variables:
- template: common-variables.yml
- name: AzDOProjectName
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
- name: AzDOPipelineId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
- name: AzDOBuildId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
pool:
vmImage: 'windows-2019'
steps:
- ${{ if eq(parameters.useBuildManifest, true) }}:
- task: DownloadBuildArtifacts@0
displayName: Download build manifest
inputs:
buildType: specific
buildVersionToDownload: specific
project: $(AzDOProjectName)
pipeline: $(AzDOPipelineId)
buildId: $(AzDOBuildId)
artifactName: BuildManifests
- task: DownloadBuildArtifacts@0
displayName: Download Package Artifacts
inputs:
buildType: specific
buildVersionToDownload: specific
project: $(AzDOProjectName)
pipeline: $(AzDOPipelineId)
buildId: $(AzDOBuildId)
artifactName: PackageArtifacts
# This is necessary whenever we want to publish/restore to an AzDO private feed
# Since sdk-task.ps1 tries to restore packages we need to do this authentication here
# otherwise it'll complain about accessing a private feed.
- task: NuGetAuthenticate@0
displayName: 'Authenticate to AzDO Feeds'
- task: PowerShell@2
displayName: Enable cross-org publishing
inputs:
filePath: eng\common\enable-cross-org-publishing.ps1
arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
# Signing validation will optionally work with the buildmanifest file which is downloaded from
# Azure DevOps above.
- task: PowerShell@2
displayName: Validate
inputs:
filePath: eng\common\sdk-task.ps1
arguments: -task SigningValidation -restore -msbuildEngine vs
/p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts'
/p:SignCheckExclusionsFile='$(Build.SourcesDirectory)/eng/SignCheckExclusionsFile.txt'
${{ parameters.signingValidationAdditionalParameters }}
- template: ../steps/publish-logs.yml
parameters:
StageLabel: 'Validation'
JobLabel: 'Signing'
- job:
displayName: SourceLink Validation
dependsOn: setupMaestroVars
condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true')
variables:
- template: common-variables.yml
- name: AzDOProjectName
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
- name: AzDOPipelineId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
- name: AzDOBuildId
value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
pool:
vmImage: 'windows-2019'
steps:
- task: DownloadBuildArtifacts@0
displayName: Download Blob Artifacts
inputs:
buildType: specific
buildVersionToDownload: specific
project: $(AzDOProjectName)
pipeline: $(AzDOPipelineId)
buildId: $(AzDOBuildId)
artifactName: BlobArtifacts
- task: PowerShell@2
displayName: Validate
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1
arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/
-ExtractPath $(Agent.BuildDirectory)/Extract/
-GHRepoName $(Build.Repository.Name)
-GHCommit $(Build.SourceVersion)
-SourcelinkCliVersion $(SourceLinkCLIVersion)
continueOnError: true
- template: /eng/common/templates/job/execute-sdl.yml
parameters:
enable: ${{ parameters.SDLValidationParameters.enable }}
dependsOn: setupMaestroVars
additionalParameters: ${{ parameters.SDLValidationParameters.params }}
continueOnError: ${{ parameters.SDLValidationParameters.continueOnError }}
artifactNames: ${{ parameters.SDLValidationParameters.artifactNames }}
downloadArtifacts: ${{ parameters.SDLValidationParameters.downloadArtifacts }}
- ${{ if and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')) }}:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -272,20 +283,24 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
stageName: 'Net5_Preview7_Publish'
channelName: '.NET 5 Preview 7'
akaMSChannelName: 'net5/preview7'
channelId: ${{ parameters.Net5Preview7ChannelId }}
transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-transport/nuget/v3/index.json'
shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json'
symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-symbols/nuget/v3/index.json'
stageName: 'NetCore_Dev6_Publish'
channelName: '.NET 6 Dev'
akaMSChannelName: 'net6/dev'
channelId: ${{ parameters.NetDev6ChannelId }}
transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6-transport/nuget/v3/index.json'
shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json'
symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6-symbols/nuget/v3/index.json'
- template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -298,8 +313,10 @@ stages:
shippingFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal/nuget/v3/index.json'
symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal-symbols/nuget/v3/index.json'
- template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -308,12 +325,14 @@ stages:
channelName: '.NET 5 RC 1'
akaMSChannelName: 'net5/rc1'
channelId: ${{ parameters.Net5RC1ChannelId }}
transportFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal-transport/nuget/v3/index.json'
shippingFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal/nuget/v3/index.json'
symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal-symbols/nuget/v3/index.json'
transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-transport/nuget/v3/index.json'
shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json'
symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-symbols/nuget/v3/index.json'
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -328,6 +347,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -342,6 +363,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -356,6 +379,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -369,6 +394,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -382,6 +409,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -395,6 +424,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -408,6 +439,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -421,6 +454,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -434,6 +469,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -447,6 +484,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -460,6 +499,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -473,6 +514,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -486,6 +529,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -499,6 +544,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -512,6 +559,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -525,6 +574,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}

View File

@ -1,25 +1,23 @@
parameters:
BARBuildId: ''
PromoteToChannelIds: ''
jobs:
- job: setupMaestroVars
displayName: Setup Maestro Vars
variables:
- template: common-variables.yml
- name: BuildId
value: $[ coalesce(variables.BARBuildId, 0) ]
- name: PromoteToMaestroChannels
value: $[ coalesce(variables.PromoteToChannelIds, 0) ]
- name: PromoteToMaestroChannel
value: $[ coalesce(variables.PromoteToMaestroChannelId, 0) ]
pool:
vmImage: 'windows-2019'
steps:
- checkout: none
- task: DownloadBuildArtifacts@0
displayName: Download Release Configs
condition: and(eq(variables.PromoteToMaestroChannels, 0), eq(variables.PromoteToMaestroChannel, 0))
inputs:
buildType: current
artifactName: ReleaseConfigs
- ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}:
- task: DownloadBuildArtifacts@0
displayName: Download Release Configs
inputs:
buildType: current
artifactName: ReleaseConfigs
- task: PowerShell@2
name: setReleaseVars
@ -28,7 +26,7 @@ jobs:
targetType: inline
script: |
try {
if ($Env:PromoteToMaestroChannels -eq 0 -and $Env:PromoteToMaestroChannel -eq 0) {
if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') {
$Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt
$BarId = $Content | Select -Index 0
@ -51,7 +49,7 @@ jobs:
$BarId = $Env:BARBuildId
$Channels = $Env:PromoteToMaestroChannels -split ","
$Channels = $Channels -join "]["
$Channels = "[$Channels][$Env:PromoteToMaestroChannel]"
$Channels = "[$Channels]"
$IsStableBuild = $buildInfo.stable
$AzureDevOpsProject = $buildInfo.azureDevOpsProject
@ -75,3 +73,5 @@ jobs:
}
env:
MAESTRO_API_TOKEN: $(MaestroApiAccessToken)
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }}

View File

@ -28,8 +28,8 @@ param(
& $PSScriptRoot\Download.ps1 "https://dot.net/v1/dotnet-install.ps1" $PSScriptRoot\dotnet-install.ps1
Write-Host "Download of dotnet-install.ps1 complete..."
Write-Host "Installing SDK...& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Version $sdkVersion -InstallDir $installDir"
Invoke-Expression "& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Version $sdkVersion -InstallDir $installDir"
Write-Host "Installing Runtime...& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Runtime dotnet -Version $runtimeVersion -InstallDir $installDir"
Invoke-Expression "& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Runtime dotnet -Version $runtimeVersion -InstallDir $installDir"
Write-Host "InstallDotNet.ps1 complete..."
Write-Host "Installing SDK...& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Version $sdkVersion -InstallDir $installDir -NoPath"
Invoke-Expression "& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Version $sdkVersion -InstallDir $installDir -NoPath"
Write-Host "Installing Runtime...& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Runtime dotnet -Version $runtimeVersion -InstallDir $installDir -NoPath"
Invoke-Expression "& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Runtime dotnet -Version $runtimeVersion -InstallDir $installDir -NoPath"
Write-Host "InstallDotNet.ps1 complete..."

View File

@ -30,7 +30,7 @@
},
"msbuild-sdks": {
"Yarn.MSBuild": "1.15.2",
"Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20411.8",
"Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.20411.8"
"Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20419.21",
"Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.20419.21"
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
@ -57,7 +58,24 @@ namespace Microsoft.AspNetCore.Antiforgery
{
// Check the content-type before accessing the form collection to make sure
// we report errors gracefully.
var form = await httpContext.Request.ReadFormAsync();
IFormCollection form;
try
{
form = await httpContext.Request.ReadFormAsync();
}
catch (InvalidDataException ex)
{
// ReadFormAsync can throw InvalidDataException if the form content is malformed.
// Wrap it in an AntiforgeryValidationException and allow the caller to handle it as just another antiforgery failure.
throw new AntiforgeryValidationException(Resources.AntiforgeryToken_UnableToReadRequest, ex);
}
catch (IOException ex)
{
// Reading the request body (which happens as part of ReadFromAsync) may throw an exception if a client disconnects.
// Wrap it in an AntiforgeryValidationException and allow the caller to handle it as just another antiforgery failure.
throw new AntiforgeryValidationException(Resources.AntiforgeryToken_UnableToReadRequest, ex);
}
requestToken = form[_options.FormFieldName];
}

View File

@ -136,6 +136,9 @@
<data name="AntiforgeryToken_TokensSwapped" xml:space="preserve">
<value>Validation of the provided antiforgery token failed. The cookie token and the request token were swapped.</value>
</data>
<data name="AntiforgeryToken_UnableToReadRequest" xml:space="preserve">
<value>Unable to read the antiforgery request token from the posted form.</value>
</data>
<data name="AntiforgeryToken_UsernameMismatch" xml:space="preserve">
<value>The provided antiforgery token was meant for user "{0}", but the current user is "{1}".</value>
</data>

View File

@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
@ -235,6 +237,56 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
Assert.Null(tokenSet.RequestToken);
}
[Fact]
public async Task GetRequestTokens_ReadFormAsyncThrowsIOException_ThrowsAntiforgeryValidationException()
{
// Arrange
var ioException = new IOException();
var httpContext = new Mock<HttpContext>();
httpContext.Setup(r => r.Request.Cookies).Returns(Mock.Of<IRequestCookieCollection>());
httpContext.SetupGet(r => r.Request.HasFormContentType).Returns(true);
httpContext.Setup(r => r.Request.ReadFormAsync(It.IsAny<CancellationToken>())).Throws(ioException);
var options = new AntiforgeryOptions
{
Cookie = { Name = "cookie-name" },
FormFieldName = "form-field-name",
HeaderName = null,
};
var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options));
// Act & Assert
var ex = await Assert.ThrowsAsync<AntiforgeryValidationException>(() => tokenStore.GetRequestTokensAsync(httpContext.Object));
Assert.Same(ioException, ex.InnerException);
}
[Fact]
public async Task GetRequestTokens_ReadFormAsyncThrowsInvalidDataException_ThrowsAntiforgeryValidationException()
{
// Arrange
var exception = new InvalidDataException();
var httpContext = new Mock<HttpContext>();
httpContext.Setup(r => r.Request.Cookies).Returns(Mock.Of<IRequestCookieCollection>());
httpContext.SetupGet(r => r.Request.HasFormContentType).Returns(true);
httpContext.Setup(r => r.Request.ReadFormAsync(It.IsAny<CancellationToken>())).Throws(exception);
var options = new AntiforgeryOptions
{
Cookie = { Name = "cookie-name" },
FormFieldName = "form-field-name",
HeaderName = null,
};
var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options));
// Act & Assert
var ex = await Assert.ThrowsAsync<AntiforgeryValidationException>(() => tokenStore.GetRequestTokensAsync(httpContext.Object));
Assert.Same(exception, ex.InnerException);
}
[Theory]
[InlineData(false, CookieSecurePolicy.SameAsRequest, null)]
[InlineData(true, CookieSecurePolicy.SameAsRequest, true)]

View File

@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Components
(
propertyName: property.Name,
propertyType: property.PropertyType,
setter: MemberAssignment.CreatePropertySetter(type, property, cascading: false)
setter: new PropertySetter(type, property)
)).ToArray();
return Initialize;

View File

@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.Components.Reflection
}
}
static void SetProperty(object target, IPropertySetter writer, string parameterName, object value)
static void SetProperty(object target, PropertySetter writer, string parameterName, object value)
{
try
{
@ -246,13 +246,13 @@ namespace Microsoft.AspNetCore.Components.Reflection
private class WritersForType
{
private const int MaxCachedWriterLookups = 100;
private readonly Dictionary<string, IPropertySetter> _underlyingWriters;
private readonly ConcurrentDictionary<string, IPropertySetter?> _referenceEqualityWritersCache;
private readonly Dictionary<string, PropertySetter> _underlyingWriters;
private readonly ConcurrentDictionary<string, PropertySetter?> _referenceEqualityWritersCache;
public WritersForType(Type targetType)
{
_underlyingWriters = new Dictionary<string, IPropertySetter>(StringComparer.OrdinalIgnoreCase);
_referenceEqualityWritersCache = new ConcurrentDictionary<string, IPropertySetter?>(ReferenceEqualityComparer.Instance);
_underlyingWriters = new Dictionary<string, PropertySetter>(StringComparer.OrdinalIgnoreCase);
_referenceEqualityWritersCache = new ConcurrentDictionary<string, PropertySetter?>(ReferenceEqualityComparer.Instance);
foreach (var propertyInfo in GetCandidateBindableProperties(targetType))
{
@ -271,7 +271,10 @@ namespace Microsoft.AspNetCore.Components.Reflection
$"The type '{targetType.FullName}' declares a parameter matching the name '{propertyName}' that is not public. Parameters must be public.");
}
var propertySetter = MemberAssignment.CreatePropertySetter(targetType, propertyInfo, cascading: cascadingParameterAttribute != null);
var propertySetter = new PropertySetter(targetType, propertyInfo)
{
Cascading = cascadingParameterAttribute != null,
};
if (_underlyingWriters.ContainsKey(propertyName))
{
@ -298,17 +301,17 @@ namespace Microsoft.AspNetCore.Components.Reflection
ThrowForInvalidCaptureUnmatchedValuesParameterType(targetType, propertyInfo);
}
CaptureUnmatchedValuesWriter = MemberAssignment.CreatePropertySetter(targetType, propertyInfo, cascading: false);
CaptureUnmatchedValuesWriter = new PropertySetter(targetType, propertyInfo);
CaptureUnmatchedValuesPropertyName = propertyInfo.Name;
}
}
}
public IPropertySetter? CaptureUnmatchedValuesWriter { get; }
public PropertySetter? CaptureUnmatchedValuesWriter { get; }
public string? CaptureUnmatchedValuesPropertyName { get; }
public bool TryGetValue(string parameterName, [MaybeNullWhen(false)] out IPropertySetter writer)
public bool TryGetValue(string parameterName, [MaybeNullWhen(false)] out PropertySetter writer)
{
// In intensive parameter-passing scenarios, one of the most expensive things we do is the
// lookup from parameterName to writer. Pre-5.0 that was because of the string hashing.

View File

@ -1,12 +1,55 @@
// 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.Reflection;
namespace Microsoft.AspNetCore.Components.Reflection
{
internal interface IPropertySetter
internal sealed class PropertySetter
{
bool Cascading { get; }
private static readonly MethodInfo CallPropertySetterOpenGenericMethod =
typeof(PropertySetter).GetMethod(nameof(CallPropertySetter), BindingFlags.NonPublic | BindingFlags.Static)!;
void SetValue(object target, object value);
private readonly Action<object, object> _setterDelegate;
public PropertySetter(Type targetType, PropertyInfo property)
{
if (property.SetMethod == null)
{
throw new InvalidOperationException($"Cannot provide a value for property " +
$"'{property.Name}' on type '{targetType.FullName}' because the property " +
$"has no setter.");
}
var setMethod = property.SetMethod;
var propertySetterAsAction =
setMethod.CreateDelegate(typeof(Action<,>).MakeGenericType(targetType, property.PropertyType));
var callPropertySetterClosedGenericMethod =
CallPropertySetterOpenGenericMethod.MakeGenericMethod(targetType, property.PropertyType);
_setterDelegate = (Action<object, object>)
callPropertySetterClosedGenericMethod.CreateDelegate(typeof(Action<object, object>), propertySetterAsAction);
}
public bool Cascading { get; init; }
public void SetValue(object target, object value) => _setterDelegate(target, value);
private static void CallPropertySetter<TTarget, TValue>(
Action<TTarget, TValue> setter,
object target,
object value)
where TTarget : notnull
{
if (value == null)
{
setter((TTarget)target, default!);
}
else
{
setter((TTarget)target, (TValue)value);
}
}
}
}

View File

@ -44,46 +44,5 @@ namespace Microsoft.AspNetCore.Components.Reflection
return dictionary.Values.SelectMany(p => p);
}
public static IPropertySetter CreatePropertySetter(Type targetType, PropertyInfo property, bool cascading)
{
if (property.SetMethod == null)
{
throw new InvalidOperationException($"Cannot provide a value for property " +
$"'{property.Name}' on type '{targetType.FullName}' because the property " +
$"has no setter.");
}
return (IPropertySetter)Activator.CreateInstance(
typeof(PropertySetter<,>).MakeGenericType(targetType, property.PropertyType),
property.SetMethod,
cascading)!;
}
class PropertySetter<TTarget, TValue> : IPropertySetter where TTarget : notnull
{
private readonly Action<TTarget, TValue> _setterDelegate;
public PropertySetter(MethodInfo setMethod, bool cascading)
{
_setterDelegate = (Action<TTarget, TValue>)Delegate.CreateDelegate(
typeof(Action<TTarget, TValue>), setMethod);
Cascading = cascading;
}
public bool Cascading { get; }
public void SetValue(object target, object value)
{
if (value == null)
{
_setterDelegate((TTarget)target, default!);
}
else
{
_setterDelegate((TTarget)target, (TValue)value);
}
}
}
}
}

View File

@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Components.Routing
/// <summary>
/// Gets or sets a handler that should be called before navigating to a new page.
/// </summary>
[Parameter] public Func<NavigationContext, Task>? OnNavigateAsync { get; set; }
[Parameter] public EventCallback<NavigationContext> OnNavigateAsync { get; set; }
private RouteTable Routes { get; set; }
@ -115,8 +115,7 @@ namespace Microsoft.AspNetCore.Components.Routing
if (!_onNavigateCalled)
{
_onNavigateCalled = true;
await RunOnNavigateWithRefreshAsync(NavigationManager.ToBaseRelativePath(_locationAbsolute), isNavigationIntercepted: false);
return;
await RunOnNavigateAsync(NavigationManager.ToBaseRelativePath(_locationAbsolute), isNavigationIntercepted: false);
}
Refresh(isNavigationIntercepted: false);
@ -206,9 +205,8 @@ namespace Microsoft.AspNetCore.Components.Routing
}
}
private async ValueTask<bool> RunOnNavigateAsync(string path, Task previousOnNavigate)
internal async ValueTask RunOnNavigateAsync(string path, bool isNavigationIntercepted)
{
// Cancel the CTS instead of disposing it, since disposing does not
// actually cancel and can cause unintended Object Disposed Exceptions.
// This effectivelly cancels the previously running task and completes it.
@ -217,59 +215,35 @@ namespace Microsoft.AspNetCore.Components.Routing
// before starting the next one. This avoid race conditions where the cancellation
// for the previous task was set but not fully completed by the time we get to this
// invocation.
await previousOnNavigate;
await _previousOnNavigateTask;
if (OnNavigateAsync == null)
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
_previousOnNavigateTask = tcs.Task;
if (!OnNavigateAsync.HasDelegate)
{
return true;
Refresh(isNavigationIntercepted);
}
_onNavigateCts = new CancellationTokenSource();
var navigateContext = new NavigationContext(path, _onNavigateCts.Token);
var cancellationTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
navigateContext.CancellationToken.Register(state =>
((TaskCompletionSource)state).SetResult(), cancellationTcs);
try
{
if (Navigating != null)
{
_renderHandle.Render(Navigating);
}
await OnNavigateAsync(navigateContext);
return true;
}
catch (OperationCanceledException e)
{
if (e.CancellationToken != navigateContext.CancellationToken)
{
var rethrownException = new InvalidOperationException("OnNavigateAsync can only be cancelled via NavigateContext.CancellationToken.", e);
_renderHandle.Render(builder => ExceptionDispatchInfo.Throw(rethrownException));
}
// Task.WhenAny returns a Task<Task> so we need to await twice to unwrap the exception
var task = await Task.WhenAny(OnNavigateAsync.InvokeAsync(navigateContext), cancellationTcs.Task);
await task;
tcs.SetResult();
Refresh(isNavigationIntercepted);
}
catch (Exception e)
{
_renderHandle.Render(builder => ExceptionDispatchInfo.Throw(e));
}
return false;
}
internal async Task RunOnNavigateWithRefreshAsync(string path, bool isNavigationIntercepted)
{
// We cache the Task representing the previously invoked RunOnNavigateWithRefreshAsync
// that is stored. Then we create a new one that represents our current invocation and store it
// globally for the next invocation. This allows us to check inside `RunOnNavigateAsync` if the
// previous OnNavigateAsync task has fully completed before starting the next one.
var previousTask = _previousOnNavigateTask;
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
_previousOnNavigateTask = tcs.Task;
// And pass an indicator for the previous task to the currently running one.
var shouldRefresh = await RunOnNavigateAsync(path, previousTask);
tcs.SetResult();
if (shouldRefresh)
{
Refresh(isNavigationIntercepted);
}
}
private void OnLocationChanged(object sender, LocationChangedEventArgs args)
@ -277,7 +251,7 @@ namespace Microsoft.AspNetCore.Components.Routing
_locationAbsolute = args.Location;
if (_renderHandle.IsInitialized && Routes != null)
{
_ = RunOnNavigateWithRefreshAsync(NavigationManager.ToBaseRelativePath(_locationAbsolute), args.IsNavigationIntercepted);
_ = RunOnNavigateAsync(NavigationManager.ToBaseRelativePath(_locationAbsolute), args.IsNavigationIntercepted);
}
}

View File

@ -10,9 +10,7 @@ using Microsoft.AspNetCore.Components.Test.Helpers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;
using Microsoft.AspNetCore.Components;
namespace Microsoft.AspNetCore.Components.Test.Routing
{
@ -42,49 +40,26 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
{
// Arrange
var called = false;
async Task OnNavigateAsync(NavigationContext args)
Action<NavigationContext> OnNavigateAsync = async (NavigationContext args) =>
{
await Task.CompletedTask;
called = true;
}
_router.OnNavigateAsync = OnNavigateAsync;
};
_router.OnNavigateAsync = new EventCallback<NavigationContext>(null, OnNavigateAsync);
// Act
await _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false));
await _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/jan", false));
// Assert
Assert.True(called);
}
[Fact]
public async Task CanHandleSingleFailedOnNavigateAsync()
{
// Arrange
var called = false;
async Task OnNavigateAsync(NavigationContext args)
{
called = true;
await Task.CompletedTask;
throw new Exception("This is an uncaught exception.");
}
_router.OnNavigateAsync = OnNavigateAsync;
// Act
await _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false));
// Assert
Assert.True(called);
Assert.Single(_renderer.HandledExceptions);
var unhandledException = _renderer.HandledExceptions[0];
Assert.Equal("This is an uncaught exception.", unhandledException.Message);
}
[Fact]
public async Task CanceledFailedOnNavigateAsyncDoesNothing()
{
// Arrange
var onNavigateInvoked = 0;
async Task OnNavigateAsync(NavigationContext args)
Action<NavigationContext> OnNavigateAsync = async (NavigationContext args) =>
{
onNavigateInvoked += 1;
if (args.Path.EndsWith("jan"))
@ -92,22 +67,18 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
await Task.Delay(Timeout.Infinite, args.CancellationToken);
throw new Exception("This is an uncaught exception.");
}
}
var refreshCalled = false;
};
var refreshCalled = 0;
_renderer.OnUpdateDisplay = (renderBatch) =>
{
if (!refreshCalled)
{
refreshCalled = true;
return;
}
Assert.True(false, "OnUpdateDisplay called more than once.");
refreshCalled += 1;
return;
};
_router.OnNavigateAsync = OnNavigateAsync;
_router.OnNavigateAsync = new EventCallback<NavigationContext>(null, OnNavigateAsync);
// Act
var janTask = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false));
var febTask = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/feb", false));
var janTask = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/jan", false));
var febTask = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/feb", false));
await janTask;
await febTask;
@ -115,28 +86,7 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
// Assert that we render the second route component and don't throw an exception
Assert.Empty(_renderer.HandledExceptions);
Assert.Equal(2, onNavigateInvoked);
}
[Fact]
public async Task CanHandleSingleCancelledOnNavigateAsync()
{
// Arrange
async Task OnNavigateAsync(NavigationContext args)
{
var tcs = new TaskCompletionSource<int>();
tcs.TrySetCanceled();
await tcs.Task;
}
_renderer.OnUpdateDisplay = (renderBatch) => Assert.True(false, "OnUpdateDisplay called more than once.");
_router.OnNavigateAsync = OnNavigateAsync;
// Act
await _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false));
// Assert
Assert.Single(_renderer.HandledExceptions);
var unhandledException = _renderer.HandledExceptions[0];
Assert.Equal("OnNavigateAsync can only be cancelled via NavigateContext.CancellationToken.", unhandledException.Message);
Assert.Equal(2, refreshCalled);
}
[Fact]
@ -144,7 +94,7 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
{
// Arrange
var triggerCancel = new TaskCompletionSource();
async Task OnNavigateAsync(NavigationContext args)
Action<NavigationContext> OnNavigateAsync = async (NavigationContext args) =>
{
if (args.Path.EndsWith("jan"))
{
@ -153,7 +103,7 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
tcs.TrySetCanceled();
await tcs.Task;
}
}
};
var refreshCalled = false;
_renderer.OnUpdateDisplay = (renderBatch) =>
{
@ -164,11 +114,11 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
}
Assert.True(false, "OnUpdateDisplay called more than once.");
};
_router.OnNavigateAsync = OnNavigateAsync;
_router.OnNavigateAsync = new EventCallback<NavigationContext>(null, OnNavigateAsync);
// Act (start the operations then await them)
var jan = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false));
var feb = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/feb", false));
var jan = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/jan", false));
var feb = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/feb", false));
triggerCancel.TrySetResult();
await jan;
@ -180,16 +130,16 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
{
// Arrange
var cancelled = "";
async Task OnNavigateAsync(NavigationContext args)
Action<NavigationContext> OnNavigateAsync = async (NavigationContext args) =>
{
await Task.CompletedTask;
args.CancellationToken.Register(() => cancelled = args.Path);
};
_router.OnNavigateAsync = OnNavigateAsync;
_router.OnNavigateAsync = new EventCallback<NavigationContext>(null, OnNavigateAsync);
// Act
_ = _router.RunOnNavigateWithRefreshAsync("jan", false);
_ = _router.RunOnNavigateWithRefreshAsync("feb", false);
_ = _router.RunOnNavigateAsync("jan", false);
_ = _router.RunOnNavigateAsync("feb", false);
// Assert
var expected = "jan";
@ -200,7 +150,7 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
public async Task RefreshesOnceOnCancelledOnNavigateAsync()
{
// Arrange
async Task OnNavigateAsync(NavigationContext args)
Action<NavigationContext> OnNavigateAsync = async (NavigationContext args) =>
{
if (args.Path.EndsWith("jan"))
{
@ -217,11 +167,11 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
}
Assert.True(false, "OnUpdateDisplay called more than once.");
};
_router.OnNavigateAsync = OnNavigateAsync;
_router.OnNavigateAsync = new EventCallback<NavigationContext>(null, OnNavigateAsync);
// Act
var jan = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false));
var feb = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/feb", false));
var jan = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/jan", false));
var feb = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/feb", false));
await jan;
await feb;

View File

@ -22,6 +22,10 @@
"src\\Components\\WebAssembly\\DebugProxy\\src\\Microsoft.AspNetCore.Components.WebAssembly.DebugProxy.csproj",
"src\\Components\\WebAssembly\\DevServer\\src\\Microsoft.AspNetCore.Components.WebAssembly.DevServer.csproj",
"src\\Components\\WebAssembly\\JSInterop\\src\\Microsoft.JSInterop.WebAssembly.csproj",
"src\\Components\\WebAssembly\\Sdk\\integrationtests\\Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests.csproj",
"src\\Components\\WebAssembly\\Sdk\\src\\Microsoft.NET.Sdk.BlazorWebAssembly.csproj",
"src\\Components\\WebAssembly\\Sdk\\test\\Microsoft.NET.Sdk.BlazorWebAssembly.Tests.csproj",
"src\\Components\\WebAssembly\\Sdk\\tools\\Microsoft.NET.Sdk.BlazorWebAssembly.Tools.csproj",
"src\\Components\\WebAssembly\\Server\\src\\Microsoft.AspNetCore.Components.WebAssembly.Server.csproj",
"src\\Components\\WebAssembly\\Server\\test\\Microsoft.AspNetCore.Components.WebAssembly.Server.Tests.csproj",
"src\\Components\\WebAssembly\\WebAssembly.Authentication\\src\\Microsoft.AspNetCore.Components.WebAssembly.Authentication.csproj",
@ -31,10 +35,9 @@
"src\\Components\\WebAssembly\\testassets\\HostedInAspNet.Client\\HostedInAspNet.Client.csproj",
"src\\Components\\WebAssembly\\testassets\\HostedInAspNet.Server\\HostedInAspNet.Server.csproj",
"src\\Components\\WebAssembly\\testassets\\StandaloneApp\\StandaloneApp.csproj",
"src\\Components\\WebAssembly\\Sdk\\src\\Microsoft.NET.Sdk.BlazorWebAssembly.csproj",
"src\\Components\\WebAssembly\\Sdk\\test\\Microsoft.NET.Sdk.BlazorWebAssembly.Tests.csproj",
"src\\Components\\WebAssembly\\Sdk\\tools\\Microsoft.NET.Sdk.BlazorWebAssembly.Tools.csproj",
"src\\Components\\WebAssembly\\Sdk\\integrationtests\\Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests.csproj",
"src\\Components\\WebAssembly\\testassets\\Wasm.Authentication.Client\\Wasm.Authentication.Client.csproj",
"src\\Components\\WebAssembly\\testassets\\Wasm.Authentication.Server\\Wasm.Authentication.Server.csproj",
"src\\Components\\WebAssembly\\testassets\\Wasm.Authentication.Shared\\Wasm.Authentication.Shared.csproj",
"src\\Components\\Web\\src\\Microsoft.AspNetCore.Components.Web.csproj",
"src\\Components\\Web\\test\\Microsoft.AspNetCore.Components.Web.Tests.csproj",
"src\\Components\\benchmarkapps\\Wasm.Performance\\ConsoleHost\\Wasm.Performance.ConsoleHost.csproj",

View File

@ -31,6 +31,7 @@ namespace Microsoft.AspNetCore.Components.Forms
// really don't, you can pass an empty object then ignore it. Ensuring it's nonnull
// simplifies things for all consumers of EditContext.
Model = model ?? throw new ArgumentNullException(nameof(model));
Properties = new EditContextProperties();
}
/// <summary>
@ -62,6 +63,11 @@ namespace Microsoft.AspNetCore.Components.Forms
/// </summary>
public object Model { get; }
/// <summary>
/// Gets a collection of arbitrary properties associated with this instance.
/// </summary>
public EditContextProperties Properties { get; }
/// <summary>
/// Signals that the value for the specified field has changed.
/// </summary>

View File

@ -0,0 +1,63 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.AspNetCore.Components.Forms
{
/// <summary>
/// Holds arbitrary key/value pairs associated with an <see cref="EditContext"/>.
/// This can be used to track additional metadata for application-specific purposes.
/// </summary>
public sealed class EditContextProperties
{
// We don't want to expose any way of enumerating the underlying dictionary, because that would
// prevent its usage to store private information. So we only expose an indexer and TryGetValue.
private Dictionary<object, object>? _contents;
/// <summary>
/// Gets or sets a value in the collection.
/// </summary>
/// <param name="key">The key under which the value is stored.</param>
/// <returns>The stored value.</returns>
public object this[object key]
{
get => _contents is null ? throw new KeyNotFoundException() : _contents[key];
set
{
_contents ??= new Dictionary<object, object>();
_contents[key] = value;
}
}
/// <summary>
/// Gets the value associated with the specified key, if any.
/// </summary>
/// <param name="key">The key under which the value is stored.</param>
/// <param name="value">The value, if present.</param>
/// <returns>True if the value was present, otherwise false.</returns>
public bool TryGetValue(object key, [NotNullWhen(true)] out object? value)
{
if (_contents is null)
{
value = default;
return false;
}
else
{
return _contents.TryGetValue(key, out value);
}
}
/// <summary>
/// Removes the specified entry from the collection.
/// </summary>
/// <param name="key">The key of the entry to be removed.</param>
/// <returns>True if the value was present, otherwise false.</returns>
public bool Remove(object key)
{
return _contents?.Remove(key) ?? false;
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
@ -252,6 +253,76 @@ namespace Microsoft.AspNetCore.Components.Forms
Assert.True(editContext.IsModified(editContext.Field(nameof(EquatableModel.Property))));
}
[Fact]
public void Properties_CanRetrieveViaIndexer()
{
// Arrange
var editContext = new EditContext(new object());
var key1 = new object();
var key2 = new object();
var key3 = new object();
var value1 = new object();
var value2 = new object();
// Initially, the values are not present
Assert.Throws<KeyNotFoundException>(() => editContext.Properties[key1]);
// Can store and retrieve values
editContext.Properties[key1] = value1;
editContext.Properties[key2] = value2;
Assert.Same(value1, editContext.Properties[key1]);
Assert.Same(value2, editContext.Properties[key2]);
// Unrelated keys are still not found
Assert.Throws<KeyNotFoundException>(() => editContext.Properties[key3]);
}
[Fact]
public void Properties_CanRetrieveViaTryGetValue()
{
// Arrange
var editContext = new EditContext(new object());
var key1 = new object();
var key2 = new object();
var key3 = new object();
var value1 = new object();
var value2 = new object();
// Initially, the values are not present
Assert.False(editContext.Properties.TryGetValue(key1, out _));
// Can store and retrieve values
editContext.Properties[key1] = value1;
editContext.Properties[key2] = value2;
Assert.True(editContext.Properties.TryGetValue(key1, out var retrievedValue1));
Assert.True(editContext.Properties.TryGetValue(key2, out var retrievedValue2));
Assert.Same(value1, retrievedValue1);
Assert.Same(value2, retrievedValue2);
// Unrelated keys are still not found
Assert.False(editContext.Properties.TryGetValue(key3, out _));
}
[Fact]
public void Properties_CanRemove()
{
// Arrange
var editContext = new EditContext(new object());
var key = new object();
var value = new object();
editContext.Properties[key] = value;
// Act
var resultForExistingKey = editContext.Properties.Remove(key);
var resultForNonExistingKey = editContext.Properties.Remove(new object());
// Assert
Assert.True(resultForExistingKey);
Assert.False(resultForNonExistingKey);
Assert.False(editContext.Properties.TryGetValue(key, out _));
Assert.Throws<KeyNotFoundException>(() => editContext.Properties[key]);
}
class EquatableModel : IEquatable<EquatableModel>
{
public string Property { get; set; } = "";

View File

@ -353,7 +353,7 @@ namespace Ignitor
_hubConnection = builder.Build();
HubConnection.On<int, string>("JS.AttachComponent", OnAttachComponent);
HubConnection.On<int, string, string>("JS.BeginInvokeJS", OnBeginInvokeJS);
HubConnection.On<int, string, string, int, long>("JS.BeginInvokeJS", OnBeginInvokeJS);
HubConnection.On<string>("JS.EndInvokeDotNet", OnEndInvokeDotNet);
HubConnection.On<int, byte[]>("JS.RenderBatch", OnRenderBatch);
HubConnection.On<string>("JS.Error", OnError);
@ -401,9 +401,9 @@ namespace Ignitor
NextAttachComponentReceived?.Completion?.TrySetResult(call);
}
private void OnBeginInvokeJS(int asyncHandle, string identifier, string argsJson)
private void OnBeginInvokeJS(int asyncHandle, string identifier, string argsJson, int resultType, long targetInstanceId)
{
var call = new CapturedJSInteropCall(asyncHandle, identifier, argsJson);
var call = new CapturedJSInteropCall(asyncHandle, identifier, argsJson, resultType, targetInstanceId);
Operations?.JSInteropCalls.Enqueue(call);
JSInterop?.Invoke(call);

View File

@ -5,15 +5,19 @@ namespace Ignitor
{
public class CapturedJSInteropCall
{
public CapturedJSInteropCall(int asyncHandle, string identifier, string argsJson)
public CapturedJSInteropCall(int asyncHandle, string identifier, string argsJson, int resultType, long targetInstanceId)
{
AsyncHandle = asyncHandle;
Identifier = identifier;
ArgsJson = argsJson;
ResultType = resultType;
TargetInstanceId = targetInstanceId;
}
public int AsyncHandle { get; }
public string Identifier { get; }
public string ArgsJson { get; }
public int ResultType { get; }
public long TargetInstanceId { get; }
}
}

View File

@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
JsonSerializer.Serialize(new[] { callId, success, resultOrError }, JsonSerializerOptions));
}
protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson)
protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson, JSCallResultType resultType, long targetInstanceId)
{
if (_clientProxy is null)
{
@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
Log.BeginInvokeJS(_logger, asyncHandle, identifier);
_clientProxy.SendAsync("JS.BeginInvokeJS", asyncHandle, identifier, argsJson);
_clientProxy.SendAsync("JS.BeginInvokeJS", asyncHandle, identifier, argsJson, (int)resultType, targetInstanceId);
}
public static class Log

View File

@ -59,13 +59,13 @@ namespace Microsoft.AspNetCore.Components.Server
{
private readonly IDataProtector _dataProtector;
private readonly ILogger<ServerComponentDeserializer> _logger;
private readonly ServerComponentTypeCache _rootComponentTypeCache;
private readonly RootComponentTypeCache _rootComponentTypeCache;
private readonly ComponentParameterDeserializer _parametersDeserializer;
public ServerComponentDeserializer(
IDataProtectionProvider dataProtectionProvider,
ILogger<ServerComponentDeserializer> logger,
ServerComponentTypeCache rootComponentTypeCache,
RootComponentTypeCache rootComponentTypeCache,
ComponentParameterDeserializer parametersDeserializer)
{
// When we protect the data we use a time-limited data protector with the

View File

@ -57,7 +57,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<StaticFileOptions>, ConfigureStaticFilesOptions>());
services.TryAddSingleton<CircuitFactory>();
services.TryAddSingleton<ServerComponentDeserializer>();
services.TryAddSingleton<ServerComponentTypeCache>();
services.TryAddSingleton<RootComponentTypeCache>();
services.TryAddSingleton<ComponentParameterDeserializer>();
services.TryAddSingleton<ComponentParametersTypeCache>();
services.TryAddSingleton<CircuitIdFactory>();

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<Description>Runtime server features for ASP.NET Core Components.</Description>
@ -54,6 +54,8 @@
<Compile Include="$(ComponentsSharedSourceRoot)src\CacheHeaderSettings.cs" Link="Shared\CacheHeaderSettings.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\ArrayBuilder.cs" LinkBase="Circuits" />
<Compile Include="$(ComponentsSharedSourceRoot)src\ElementReferenceJsonConverter.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\ComponentParametersTypeCache.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\RootComponentTypeCache.cs" />
<Compile Include="..\..\Shared\src\BrowserNavigationManagerInterop.cs" />
<Compile Include="..\..\Shared\src\JsonSerializerOptionsProvider.cs" />

View File

@ -320,7 +320,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
return new ServerComponentDeserializer(
_ephemeralDataProtectionProvider,
NullLogger<ServerComponentDeserializer>.Instance,
new ServerComponentTypeCache(),
new RootComponentTypeCache(),
new ComponentParameterDeserializer(NullLogger<ComponentParameterDeserializer>.Instance, new ComponentParametersTypeCache()));
}

View File

@ -9,7 +9,7 @@ using System.Reflection;
namespace Microsoft.AspNetCore.Components
{
// A cache for root component types
internal class ServerComponentTypeCache
internal class RootComponentTypeCache
{
private readonly ConcurrentDictionary<Key, Type> _typeToKeyLookUp = new ConcurrentDictionary<Key, Type>();
@ -39,14 +39,14 @@ namespace Microsoft.AspNetCore.Components
return assembly.GetType(key.Type, throwOnError: false, ignoreCase: false);
}
private struct Key : IEquatable<Key>
private readonly struct Key : IEquatable<Key>
{
public Key(string assembly, string type) =>
(Assembly, Type) = (assembly, type);
public string Assembly { get; set; }
public string Assembly { get; }
public string Type { get; set; }
public string Type { get; }
public override bool Equals(object obj) => Equals((Key)obj);

View File

@ -0,0 +1,33 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Components.Web.Extensions
{
internal class BrowserFile : IBrowserFile
{
internal InputFile Owner { get; set; } = default!;
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public DateTime LastModified { get; set; }
public long Size { get; set; }
public string Type { get; set; } = string.Empty;
public string? RelativePath { get; set; }
public Stream OpenReadStream(CancellationToken cancellationToken = default)
=> Owner.OpenReadStream(this, cancellationToken);
public Task<IBrowserFile> ToImageFileAsync(string format, int maxWidth, int maxHeight)
=> Owner.ConvertToImageFileAsync(this, format, maxWidth, maxHeight);
}
}

View File

@ -0,0 +1,77 @@
// 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.Threading;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Components.Web.Extensions
{
internal abstract class BrowserFileStream : Stream
{
private long _position;
protected BrowserFile File { get; }
protected BrowserFileStream(BrowserFile file)
{
File = file;
}
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => File.Size;
public override long Position
{
get => _position;
set => throw new NotSupportedException();
}
public override void Flush()
=> throw new NotSupportedException();
public override int Read(byte[] buffer, int offset, int count)
=> throw new NotSupportedException("Synchronous reads are not supported.");
public override long Seek(long offset, SeekOrigin origin)
=> throw new NotSupportedException();
public override void SetLength(long value)
=> throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count)
=> throw new NotSupportedException();
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
=> ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
int maxBytesToRead = (int)(Length - Position);
if (maxBytesToRead > buffer.Length)
{
maxBytesToRead = buffer.Length;
}
if (maxBytesToRead <= 0)
{
return 0;
}
var bytesRead = await CopyFileDataIntoBuffer(_position, buffer.Slice(0, maxBytesToRead), cancellationToken);
_position += bytesRead;
return bytesRead;
}
protected abstract ValueTask<int> CopyFileDataIntoBuffer(long sourceOffset, Memory<byte> destination, CancellationToken cancellationToken);
}
}

View File

@ -0,0 +1,54 @@
// 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.Threading;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Components.Web.Extensions
{
/// <summary>
/// Represents the data of a file selected from an <see cref="InputFile"/> component.
/// </summary>
public interface IBrowserFile
{
/// <summary>
/// Gets the name of the file.
/// </summary>
string Name { get; }
/// <summary>
/// Gets the last modified date.
/// </summary>
DateTime LastModified { get; }
/// <summary>
/// Gets the size of the file in bytes.
/// </summary>
long Size { get; }
/// <summary>
/// Gets the MIME type of the file.
/// </summary>
string Type { get; }
/// <summary>
/// Opens the stream for reading the uploaded file.
/// </summary>
/// <param name="cancellationToken">A cancellation token to signal the cancellation of streaming file data.</param>
Stream OpenReadStream(CancellationToken cancellationToken = default);
/// <summary>
/// Converts the current image file to a new one of the specified file type and maximum file dimensions.
/// </summary>
/// <remarks>
/// The image will be scaled to fit the specified dimensions while preserving the original aspect ratio.
/// </remarks>
/// <param name="format">The new image format.</param>
/// <param name="maxWith">The maximum image width.</param>
/// <param name="maxHeight">The maximum image height</param>
/// <returns>A <see cref="Task"/> representing the completion of the operation.</returns>
Task<IBrowserFile> ToImageFileAsync(string format, int maxWith, int maxHeight);
}
}

View File

@ -0,0 +1,12 @@
// 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.Threading.Tasks;
namespace Microsoft.AspNetCore.Components.Web.Extensions
{
internal interface IInputFileJsCallbacks
{
Task NotifyChange(BrowserFile[] files);
}
}

View File

@ -0,0 +1,96 @@
// 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.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.Extensions.Options;
using Microsoft.JSInterop;
namespace Microsoft.AspNetCore.Components.Web.Extensions
{
/// <summary>
/// A component that wraps the HTML file input element and exposes a <see cref="Stream"/> for each file's contents.
/// </summary>
public class InputFile : ComponentBase, IInputFileJsCallbacks, IDisposable
{
private ElementReference _inputFileElement;
private IJSUnmarshalledRuntime? _jsUnmarshalledRuntime;
private InputFileJsCallbacksRelay? _jsCallbacksRelay;
[Inject]
private IJSRuntime JSRuntime { get; set; } = default!;
[Inject]
private IOptions<RemoteBrowserFileStreamOptions> Options { get; set; } = default!;
/// <summary>
/// Gets or sets the event callback that will be invoked when the collection of selected files changes.
/// </summary>
[Parameter]
public EventCallback<InputFileChangeEventArgs> OnChange { get; set; }
/// <summary>
/// Gets or sets a collection of additional attributes that will be applied to the input element.
/// </summary>
[Parameter(CaptureUnmatchedValues = true)]
public IDictionary<string, object>? AdditionalAttributes { get; set; }
protected override void OnInitialized()
{
_jsUnmarshalledRuntime = JSRuntime as IJSUnmarshalledRuntime;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
_jsCallbacksRelay = new InputFileJsCallbacksRelay(this);
await JSRuntime.InvokeVoidAsync(InputFileInterop.Init, _jsCallbacksRelay.DotNetReference, _inputFileElement);
}
}
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenElement(0, "input");
builder.AddMultipleAttributes(1, AdditionalAttributes);
builder.AddAttribute(2, "type", "file");
builder.AddElementReferenceCapture(3, elementReference => _inputFileElement = elementReference);
builder.CloseElement();
}
internal Stream OpenReadStream(BrowserFile file, CancellationToken cancellationToken)
=> _jsUnmarshalledRuntime != null ?
(Stream)new SharedBrowserFileStream(JSRuntime, _jsUnmarshalledRuntime, _inputFileElement, file) :
new RemoteBrowserFileStream(JSRuntime, _inputFileElement, file, Options.Value, cancellationToken);
internal async Task<IBrowserFile> ConvertToImageFileAsync(BrowserFile file, string format, int maxWidth, int maxHeight)
{
var imageFile = await JSRuntime.InvokeAsync<BrowserFile>(InputFileInterop.ToImageFile, _inputFileElement, file.Id, format, maxWidth, maxHeight);
imageFile.Owner = this;
return imageFile;
}
Task IInputFileJsCallbacks.NotifyChange(BrowserFile[] files)
{
foreach (var file in files)
{
file.Owner = this;
}
return OnChange.InvokeAsync(new InputFileChangeEventArgs(files));
}
void IDisposable.Dispose()
{
_jsCallbacksRelay?.Dispose();
}
}
}

View File

@ -0,0 +1,28 @@
// 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;
namespace Microsoft.AspNetCore.Components.Web.Extensions
{
/// <summary>
/// Supplies information about an <see cref="InputFile.OnChange"/> event being raised.
/// </summary>
public class InputFileChangeEventArgs : EventArgs
{
/// <summary>
/// The updated file entries list.
/// </summary>
public IReadOnlyList<IBrowserFile> Files { get; }
/// <summary>
/// Constructs a new <see cref="InputFileChangeEventArgs"/> instance.
/// </summary>
/// <param name="files">The updated file entries list.</param>
public InputFileChangeEventArgs(IReadOnlyList<IBrowserFile> files)
{
Files = files;
}
}
}

View File

@ -0,0 +1,20 @@
// 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.Web.Extensions
{
internal static class InputFileInterop
{
private const string JsFunctionsPrefix = "_blazorInputFile.";
public const string Init = JsFunctionsPrefix + "init";
public const string EnsureArrayBufferReadyForSharedMemoryInterop = JsFunctionsPrefix + "ensureArrayBufferReadyForSharedMemoryInterop";
public const string ReadFileData = JsFunctionsPrefix + "readFileData";
public const string ReadFileDataSharedMemory = JsFunctionsPrefix + "readFileDataSharedMemory";
public const string ToImageFile = JsFunctionsPrefix + "toImageFile";
}
}

View File

@ -0,0 +1,32 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading.Tasks;
using Microsoft.JSInterop;
namespace Microsoft.AspNetCore.Components.Web.Extensions
{
internal class InputFileJsCallbacksRelay : IDisposable
{
private readonly IInputFileJsCallbacks _callbacks;
public IDisposable DotNetReference { get; }
public InputFileJsCallbacksRelay(IInputFileJsCallbacks callbacks)
{
_callbacks = callbacks;
DotNetReference = DotNetObjectReference.Create(this);
}
[JSInvokable]
public Task NotifyChange(BrowserFile[] files)
=> _callbacks.NotifyChange(files);
public void Dispose()
{
DotNetReference.Dispose();
}
}
}

View File

@ -0,0 +1,29 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.InteropServices;
namespace Microsoft.AspNetCore.Components.Web.Extensions
{
[StructLayout(LayoutKind.Explicit)]
internal struct ReadRequest
{
[FieldOffset(0)]
public string InputFileElementReferenceId;
[FieldOffset(4)]
public int FileId;
[FieldOffset(8)]
public long SourceOffset;
[FieldOffset(16)]
public byte[] Destination;
[FieldOffset(20)]
public int DestinationOffset;
[FieldOffset(24)]
public int MaxBytes;
}
}

View File

@ -0,0 +1,145 @@
// 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.Buffers;
using System.IO.Pipelines;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.JSInterop;
namespace Microsoft.AspNetCore.Components.Web.Extensions
{
internal class RemoteBrowserFileStream : BrowserFileStream
{
private readonly IJSRuntime _jsRuntime;
private readonly ElementReference _inputFileElement;
private readonly int _maxSegmentSize;
private readonly PipeReader _pipeReader;
private readonly CancellationTokenSource _fillBufferCts;
private readonly TimeSpan _segmentFetchTimeout;
private bool _isReadingCompleted;
private bool _isDisposed;
public RemoteBrowserFileStream(
IJSRuntime jsRuntime,
ElementReference inputFileElement,
BrowserFile file,
RemoteBrowserFileStreamOptions options,
CancellationToken cancellationToken)
: base(file)
{
_jsRuntime = jsRuntime;
_inputFileElement = inputFileElement;
_maxSegmentSize = options.SegmentSize;
_segmentFetchTimeout = options.SegmentFetchTimeout;
var pipe = new Pipe(new PipeOptions(pauseWriterThreshold: options.MaxBufferSize, resumeWriterThreshold: options.MaxBufferSize));
_pipeReader = pipe.Reader;
_fillBufferCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
_ = FillBuffer(pipe.Writer, _fillBufferCts.Token);
}
private async Task FillBuffer(PipeWriter writer, CancellationToken cancellationToken)
{
long offset = 0;
while (offset < File.Size)
{
var pipeBuffer = writer.GetMemory(_maxSegmentSize);
var segmentSize = (int)Math.Min(_maxSegmentSize, File.Size - offset);
try
{
using var readSegmentCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
readSegmentCts.CancelAfter(_segmentFetchTimeout);
var bytes = await _jsRuntime.InvokeAsync<byte[]>(
InputFileInterop.ReadFileData,
readSegmentCts.Token,
_inputFileElement,
File.Id,
offset,
segmentSize);
if (bytes.Length != segmentSize)
{
throw new InvalidOperationException(
$"A segment with size {bytes.Length} bytes was received, but {segmentSize} bytes were expected.");
}
bytes.CopyTo(pipeBuffer);
writer.Advance(segmentSize);
offset += segmentSize;
var result = await writer.FlushAsync(cancellationToken);
if (result.IsCompleted)
{
break;
}
}
catch (Exception e)
{
await writer.CompleteAsync(e);
return;
}
}
await writer.CompleteAsync();
}
protected override async ValueTask<int> CopyFileDataIntoBuffer(long sourceOffset, Memory<byte> destination, CancellationToken cancellationToken)
{
if (_isReadingCompleted)
{
return 0;
}
int totalBytesCopied = 0;
while (destination.Length > 0)
{
var result = await _pipeReader.ReadAsync(cancellationToken);
var bytesToCopy = (int)Math.Min(result.Buffer.Length, destination.Length);
if (bytesToCopy == 0)
{
if (result.IsCompleted)
{
_isReadingCompleted = true;
await _pipeReader.CompleteAsync();
}
break;
}
var slice = result.Buffer.Slice(0, bytesToCopy);
slice.CopyTo(destination.Span);
_pipeReader.AdvanceTo(slice.End);
totalBytesCopied += bytesToCopy;
destination = destination.Slice(bytesToCopy);
}
return totalBytesCopied;
}
protected override void Dispose(bool disposing)
{
if (_isDisposed)
{
return;
}
_fillBufferCts.Cancel();
_isDisposed = true;
base.Dispose(disposing);
}
}
}

View File

@ -0,0 +1,40 @@
// 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.Runtime.Versioning;
namespace Microsoft.AspNetCore.Components.Web.Extensions
{
/// <summary>
/// Repesents configurable options for <see cref="RemoteBrowserFileStream"/>.
/// </summary>
[UnsupportedOSPlatform("browser")]
public class RemoteBrowserFileStreamOptions
{
/// <summary>
/// Gets or sets the maximum segment size for file data sent over a SignalR circuit.
/// The default value is 20K.
/// <para>
/// This only has an effect when using Blazor Server.
/// </para>
/// </summary>
public int SegmentSize { get; set; } = 20 * 1024; // SignalR limit is 32K.
/// <summary>
/// Gets or sets the maximum internal buffer size for unread data sent over a SignalR circuit.
/// <para>
/// This only has an effect when using Blazor Server.
/// </para>
/// </summary>
public int MaxBufferSize { get; set; } = 1024 * 1024;
/// <summary>
/// Gets or sets the time limit for fetching a segment of file data.
/// <para>
/// This only has an effect when using Blazor Server.
/// </para>
/// </summary>
public TimeSpan SegmentFetchTimeout { get; set; } = TimeSpan.FromSeconds(3);
}
}

View File

@ -0,0 +1,58 @@
// 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.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.JSInterop;
namespace Microsoft.AspNetCore.Components.Web.Extensions
{
internal class SharedBrowserFileStream : BrowserFileStream
{
private readonly IJSRuntime _jsRuntime;
private readonly IJSUnmarshalledRuntime _jsUnmarshalledRuntime;
private readonly ElementReference _inputFileElement;
public SharedBrowserFileStream(IJSRuntime jsRuntime, IJSUnmarshalledRuntime jsUnmarshalledRuntime, ElementReference inputFileElement, BrowserFile file)
: base(file)
{
_jsRuntime = jsRuntime;
_jsUnmarshalledRuntime = jsUnmarshalledRuntime;
_inputFileElement = inputFileElement;
}
protected override async ValueTask<int> CopyFileDataIntoBuffer(long sourceOffset, Memory<byte> destination, CancellationToken cancellationToken)
{
await _jsRuntime.InvokeVoidAsync(InputFileInterop.EnsureArrayBufferReadyForSharedMemoryInterop, cancellationToken, _inputFileElement, File.Id);
var readRequest = new ReadRequest
{
InputFileElementReferenceId = _inputFileElement.Id,
FileId = File.Id,
SourceOffset = sourceOffset
};
if (MemoryMarshal.TryGetArray(destination, out ArraySegment<byte> destinationArraySegment))
{
readRequest.Destination = destinationArraySegment.Array!;
readRequest.DestinationOffset = destinationArraySegment.Offset;
readRequest.MaxBytes = destinationArraySegment.Count;
}
else
{
// Worst case, we need to copy to a temporary array.
readRequest.Destination = new byte[destination.Length];
readRequest.DestinationOffset = 0;
readRequest.MaxBytes = destination.Length;
destination.CopyTo(new Memory<byte>(readRequest.Destination));
}
return _jsUnmarshalledRuntime.InvokeUnmarshalled<ReadRequest, int>(InputFileInterop.ReadFileDataSharedMemory, readRequest);
}
}
}

View File

@ -0,0 +1,142 @@
(function () {
// Exported functions
function init(callbackWrapper, elem) {
elem._blazorInputFileNextFileId = 0;
elem.addEventListener('click', function () {
// Permits replacing an existing file with a new one of the same file name.
elem.value = '';
});
elem.addEventListener('change', function () {
// Reduce to purely serializable data, plus an index by ID.
elem._blazorFilesById = {};
const fileList = Array.prototype.map.call(elem.files, function (file) {
const result = {
id: ++elem._blazorInputFileNextFileId,
lastModified: new Date(file.lastModified).toISOString(),
name: file.name,
size: file.size,
type: file.type,
};
elem._blazorFilesById[result.id] = result;
// Attach the blob data itself as a non-enumerable property so it doesn't appear in the JSON.
Object.defineProperty(result, 'blob', { value: file });
return result;
});
callbackWrapper.invokeMethodAsync('NotifyChange', fileList);
});
}
function toImageFile(elem, fileId, format, maxWidth, maxHeight) {
var originalFile = getFileById(elem, fileId);
return new Promise(function (resolve) {
var originalFileImage = new Image();
originalFileImage.onload = function () { resolve(originalFileImage); };
originalFileImage.src = URL.createObjectURL(originalFile.blob);
}).then(function (loadedImage) {
return new Promise(function (resolve) {
var desiredWidthRatio = Math.min(1, maxWidth / loadedImage.width);
var desiredHeightRatio = Math.min(1, maxHeight / loadedImage.height);
var chosenSizeRatio = Math.min(desiredWidthRatio, desiredHeightRatio);
var canvas = document.createElement('canvas');
canvas.width = Math.round(loadedImage.width * chosenSizeRatio);
canvas.height = Math.round(loadedImage.height * chosenSizeRatio);
canvas.getContext('2d').drawImage(loadedImage, 0, 0, canvas.width, canvas.height);
canvas.toBlob(resolve, format);
});
}).then(function (resizedImageBlob) {
var result = {
id: ++elem._blazorInputFileNextFileId,
lastModified: originalFile.lastModified,
name: originalFile.name, // Note: we're not changing the file extension.
size: resizedImageBlob.size,
type: format,
relativePath: originalFile.relativePath
};
elem._blazorFilesById[result.id] = result;
// Attach the blob data itself as a non-enumerable property so it doesn't appear in the JSON.
Object.defineProperty(result, 'blob', { value: resizedImageBlob });
return result;
});
}
function ensureArrayBufferReadyForSharedMemoryInterop(elem, fileId) {
return getArrayBufferFromFileAsync(elem, fileId).then(function (arrayBuffer) {
getFileById(elem, fileId).arrayBuffer = arrayBuffer;
});
}
function readFileData(elem, fileId, startOffset, count) {
return getArrayBufferFromFileAsync(elem, fileId).then(function (arrayBuffer) {
return btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer, startOffset, count)));
});
}
function readFileDataSharedMemory(readRequest) {
const inputFileElementReferenceId = Blazor.platform.readStringField(readRequest, 0);
const inputFileElement = document.querySelector(`[_bl_${inputFileElementReferenceId}]`);
const fileId = Blazor.platform.readInt32Field(readRequest, 4);
const sourceOffset = Blazor.platform.readUint64Field(readRequest, 8);
const destination = Blazor.platform.readInt32Field(readRequest, 16);
const destinationOffset = Blazor.platform.readInt32Field(readRequest, 20);
const maxBytes = Blazor.platform.readInt32Field(readRequest, 24);
const sourceArrayBuffer = getFileById(inputFileElement, fileId).arrayBuffer;
const bytesToRead = Math.min(maxBytes, sourceArrayBuffer.byteLength - sourceOffset);
const sourceUint8Array = new Uint8Array(sourceArrayBuffer, sourceOffset, bytesToRead);
const destinationUint8Array = Blazor.platform.toUint8Array(destination);
destinationUint8Array.set(sourceUint8Array, destinationOffset);
return bytesToRead;
}
// Local helpers
function getFileById(elem, fileId) {
const file = elem._blazorFilesById[fileId];
if (!file) {
throw new Error(`There is no file with ID ${fileId}. The file list may have changed.`);
}
return file;
}
function getArrayBufferFromFileAsync(elem, fileId) {
const file = getFileById(elem, fileId);
// On the first read, convert the FileReader into a Promise<ArrayBuffer>.
if (!file.readPromise) {
file.readPromise = new Promise(function (resolve, reject) {
const reader = new FileReader();
reader.onload = function () { resolve(reader.result); };
reader.onerror = function (err) { reject(err); };
reader.readAsArrayBuffer(file.blob);
});
}
return file.readPromise;
}
window._blazorInputFile = {
init,
toImageFile,
ensureArrayBufferReadyForSharedMemoryInterop,
readFileData,
readFileDataSharedMemory,
};
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -7,11 +7,12 @@ import { shouldAutoStart } from './BootCommon';
import { RenderQueue } from './Platform/Circuits/RenderQueue';
import { ConsoleLogger } from './Platform/Logging/Loggers';
import { LogLevel, Logger } from './Platform/Logging/Logger';
import { discoverComponents, CircuitDescriptor } from './Platform/Circuits/CircuitManager';
import { CircuitDescriptor } from './Platform/Circuits/CircuitManager';
import { setEventDispatcher } from './Rendering/RendererEventDispatcher';
import { resolveOptions, CircuitStartOptions } from './Platform/Circuits/CircuitStartOptions';
import { DefaultReconnectionHandler } from './Platform/Circuits/DefaultReconnectionHandler';
import { attachRootComponentToLogicalElement } from './Rendering/Renderer';
import { discoverComponents, ServerComponentDescriptor } from './Services/ComponentDescriptorDiscovery';
let renderingFailed = false;
let started = false;
@ -29,7 +30,7 @@ async function boot(userOptions?: Partial<CircuitStartOptions>): Promise<void> {
options.reconnectionHandler = options.reconnectionHandler || window['Blazor'].defaultReconnectionHandler;
logger.log(LogLevel.Information, 'Starting up blazor server-side application.');
const components = discoverComponents(document);
const components = discoverComponents(document, 'server') as ServerComponentDescriptor[];
const circuit = new CircuitDescriptor(components);
const initialConnection = await initializeConnection(options, logger, circuit);
@ -97,7 +98,7 @@ async function initializeConnection(options: CircuitStartOptions, logger: Logger
connection.on('JS.AttachComponent', (componentId, selector) => attachRootComponentToLogicalElement(0, circuit.resolveElement(selector), componentId));
connection.on('JS.BeginInvokeJS', DotNet.jsCallDispatcher.beginInvokeJSFromDotNet);
connection.on('JS.EndInvokeDotNet', (args: string) => DotNet.jsCallDispatcher.endInvokeDotNetFromJS(...(JSON.parse(args) as [string, boolean, unknown])));
connection.on('JS.EndInvokeDotNet', (args: string) => DotNet.jsCallDispatcher.endInvokeDotNetFromJS(...(DotNet.parseJsonWithRevivers(args) as [string, boolean, unknown])));
const renderQueue = RenderQueue.getOrCreate(logger);
connection.on('JS.RenderBatch', (batchId: number, batchData: Uint8Array) => {

View File

@ -2,7 +2,7 @@ import { DotNet } from '@microsoft/dotnet-js-interop';
import './GlobalExports';
import * as Environment from './Environment';
import { monoPlatform } from './Platform/Mono/MonoPlatform';
import { renderBatch, getRendererer } from './Rendering/Renderer';
import { renderBatch, getRendererer, attachRootComponentToElement, attachRootComponentToLogicalElement } from './Rendering/Renderer';
import { SharedMemoryRenderBatch } from './Rendering/RenderBatch/SharedMemoryRenderBatch';
import { shouldAutoStart } from './BootCommon';
import { setEventDispatcher } from './Rendering/RendererEventDispatcher';
@ -11,6 +11,8 @@ import { WebAssemblyConfigLoader } from './Platform/WebAssemblyConfigLoader';
import { BootConfigResult } from './Platform/BootConfig';
import { Pointer } from './Platform/Platform';
import { WebAssemblyStartOptions } from './Platform/WebAssemblyStartOptions';
import { WebAssemblyComponentAttacher } from './Platform/WebAssemblyComponentAttacher';
import { discoverComponents, WebAssemblyComponentDescriptor } from './Services/ComponentDescriptorDiscovery';
let started = false;
@ -32,6 +34,9 @@ async function boot(options?: Partial<WebAssemblyStartOptions>): Promise<void> {
}
});
// Configure JS interop
window['Blazor']._internal.invokeJSFromDotNet = invokeJSFromDotNet;
// Configure environment for execution under Mono WebAssembly with shared-memory rendering
const platform = Environment.setPlatform(monoPlatform);
window['Blazor'].platform = platform;
@ -68,8 +73,31 @@ async function boot(options?: Partial<WebAssemblyStartOptions>): Promise<void> {
const environment = options?.environment;
// Fetch the resources and prepare the Mono runtime
const bootConfigResult = await BootConfigResult.initAsync(environment);
const bootConfigPromise = BootConfigResult.initAsync(environment);
// Leverage the time while we are loading boot.config.json from the network to discover any potentially registered component on
// the document.
const discoveredComponents = discoverComponents(document, 'webassembly') as WebAssemblyComponentDescriptor[];
const componentAttacher = new WebAssemblyComponentAttacher(discoveredComponents);
window['Blazor']._internal.registeredComponents = {
getRegisteredComponentsCount: () => componentAttacher.getCount(),
getId: (index) => componentAttacher.getId(index),
getAssembly: (id) => BINDING.js_string_to_mono_string(componentAttacher.getAssembly(id)),
getTypeName: (id) => BINDING.js_string_to_mono_string(componentAttacher.getTypeName(id)),
getParameterDefinitions: (id) => BINDING.js_string_to_mono_string(componentAttacher.getParameterDefinitions(id) || ''),
getParameterValues: (id) => BINDING.js_string_to_mono_string(componentAttacher.getParameterValues(id) || ''),
};
window['Blazor']._internal.attachRootComponentToElement = (selector, componentId, rendererId) => {
const element = componentAttacher.resolveRegisteredElement(selector);
if (!element) {
attachRootComponentToElement(selector, componentId, rendererId);
} else {
attachRootComponentToLogicalElement(rendererId, element, componentId);
}
};
const bootConfigResult = await bootConfigPromise;
const [resourceLoader] = await Promise.all([
WebAssemblyResourceLoader.initAsync(bootConfigResult.bootConfig, options || {}),
WebAssemblyConfigLoader.initAsync(bootConfigResult)]);
@ -84,6 +112,28 @@ async function boot(options?: Partial<WebAssemblyStartOptions>): Promise<void> {
platform.callEntryPoint(resourceLoader.bootConfig.entryAssembly);
}
function invokeJSFromDotNet(callInfo: Pointer, arg0: any, arg1: any, arg2: any): any {
const functionIdentifier = monoPlatform.readStringField(callInfo, 0)!;
const resultType = monoPlatform.readInt32Field(callInfo, 4);
const marshalledCallArgsJson = monoPlatform.readStringField(callInfo, 8);
const targetInstanceId = monoPlatform.readUint64Field(callInfo, 20);
if (marshalledCallArgsJson !== null) {
const marshalledCallAsyncHandle = monoPlatform.readUint64Field(callInfo, 12);
if (marshalledCallAsyncHandle !== 0) {
DotNet.jsCallDispatcher.beginInvokeJSFromDotNet(marshalledCallAsyncHandle, functionIdentifier, marshalledCallArgsJson, resultType, targetInstanceId);
return 0;
} else {
const resultJson = DotNet.jsCallDispatcher.invokeJSFromDotNet(functionIdentifier, marshalledCallArgsJson, resultType, targetInstanceId)!;
return resultJson === null ? 0 : BINDING.js_string_to_mono_string(resultJson);
}
} else {
const func = DotNet.jsCallDispatcher.findJSFunction(functionIdentifier, targetInstanceId);
return func.call(null, arg0, arg1, arg2);
}
}
window['Blazor'].start = boot;
if (shouldAutoStart()) {
boot().catch(error => {

View File

@ -8,7 +8,6 @@ window['Blazor'] = {
navigateTo,
_internal: {
attachRootComponentToElement,
navigationManager: navigationManagerInternalFunctions,
domWrapper: domFunctions,
Virtualize,

View File

@ -1,12 +1,13 @@
import { internalFunctions as navigationManagerFunctions } from '../../Services/NavigationManager';
import { toLogicalRootCommentElement, LogicalElement } from '../../Rendering/LogicalElements';
import { ServerComponentDescriptor } from '../../Services/ComponentDescriptorDiscovery';
export class CircuitDescriptor {
public circuitId?: string;
public components: ComponentDescriptor[];
public components: ServerComponentDescriptor[];
public constructor(components: ComponentDescriptor[]) {
public constructor(components: ServerComponentDescriptor[]) {
this.circuitId = undefined;
this.components = components;
}
@ -54,221 +55,3 @@ export class CircuitDescriptor {
}
}
interface ComponentMarker {
type: string;
sequence: number;
descriptor: string;
}
export class ComponentDescriptor {
public type: string;
public start: Node;
public end?: Node;
public sequence: number;
public descriptor: string;
public constructor(type: string, start: Node, end: Node | undefined, sequence: number, descriptor: string) {
this.type = type;
this.start = start;
this.end = end;
this.sequence = sequence;
this.descriptor = descriptor;
}
public toRecord(): ComponentMarker {
const result = { type: this.type, sequence: this.sequence, descriptor: this.descriptor };
return result;
}
}
export function discoverComponents(document: Document): ComponentDescriptor[] {
const componentComments = resolveComponentComments(document);
const discoveredComponents: ComponentDescriptor[] = [];
for (let i = 0; i < componentComments.length; i++) {
const componentComment = componentComments[i];
const entry = new ComponentDescriptor(
componentComment.type,
componentComment.start,
componentComment.end,
componentComment.sequence,
componentComment.descriptor,
);
discoveredComponents.push(entry);
}
return discoveredComponents.sort((a, b) => a.sequence - b.sequence);
}
interface ComponentComment {
type: 'server';
sequence: number;
descriptor: string;
start: Node;
end?: Node;
prerenderId?: string;
}
function resolveComponentComments(node: Node): ComponentComment[] {
if (!node.hasChildNodes()) {
return [];
}
const result: ComponentComment[] = [];
const childNodeIterator = new ComponentCommentIterator(node.childNodes);
while (childNodeIterator.next() && childNodeIterator.currentElement) {
const componentComment = getComponentComment(childNodeIterator);
if (componentComment) {
result.push(componentComment);
} else {
const childResults = resolveComponentComments(childNodeIterator.currentElement);
for (let j = 0; j < childResults.length; j++) {
const childResult = childResults[j];
result.push(childResult);
}
}
}
return result;
}
const blazorCommentRegularExpression = /\W*Blazor:[^{]*(.*)$/;
function getComponentComment(commentNodeIterator: ComponentCommentIterator): ComponentComment | undefined {
const candidateStart = commentNodeIterator.currentElement;
if (!candidateStart || candidateStart.nodeType !== Node.COMMENT_NODE) {
return;
}
if (candidateStart.textContent) {
const componentStartComment = new RegExp(blazorCommentRegularExpression);
const definition = componentStartComment.exec(candidateStart.textContent);
const json = definition && definition[1];
if (json) {
try {
return createComponentComment(json, candidateStart, commentNodeIterator);
} catch (error) {
throw new Error(`Found malformed component comment at ${candidateStart.textContent}`);
}
} else {
return;
}
}
}
function createComponentComment(json: string, start: Node, iterator: ComponentCommentIterator): ComponentComment {
const payload = JSON.parse(json) as ComponentComment;
const { type, sequence, descriptor, prerenderId } = payload;
if (type !== 'server') {
throw new Error(`Invalid component type '${type}'.`);
}
if (!descriptor) {
throw new Error('descriptor must be defined when using a descriptor.');
}
if (sequence === undefined) {
throw new Error('sequence must be defined when using a descriptor.');
}
if (!Number.isInteger(sequence)) {
throw new Error(`Error parsing the sequence '${sequence}' for component '${json}'`);
}
if (!prerenderId) {
return {
type,
sequence: sequence,
descriptor,
start,
};
} else {
const end = getComponentEndComment(prerenderId, iterator);
if (!end) {
throw new Error(`Could not find an end component comment for '${start}'`);
}
return {
type,
sequence,
descriptor,
start,
prerenderId,
end,
};
}
}
function getComponentEndComment(prerenderedId: string, iterator: ComponentCommentIterator): ChildNode | undefined {
while (iterator.next() && iterator.currentElement) {
const node = iterator.currentElement;
if (node.nodeType !== Node.COMMENT_NODE) {
continue;
}
if (!node.textContent) {
continue;
}
const definition = new RegExp(blazorCommentRegularExpression).exec(node.textContent);
const json = definition && definition[1];
if (!json) {
continue;
}
validateEndComponentPayload(json, prerenderedId);
return node;
}
return undefined;
}
function validateEndComponentPayload(json: string, prerenderedId: string): void {
const payload = JSON.parse(json) as ComponentComment;
if (Object.keys(payload).length !== 1) {
throw new Error(`Invalid end of component comment: '${json}'`);
}
const prerenderedEndId = payload.prerenderId;
if (!prerenderedEndId) {
throw new Error(`End of component comment must have a value for the prerendered property: '${json}'`);
}
if (prerenderedEndId !== prerenderedId) {
throw new Error(`End of component comment prerendered property must match the start comment prerender id: '${prerenderedId}', '${prerenderedEndId}'`);
}
}
class ComponentCommentIterator {
private childNodes: NodeListOf<ChildNode>;
private currentIndex: number;
private length: number;
public currentElement: ChildNode | undefined;
public constructor(childNodes: NodeListOf<ChildNode>) {
this.childNodes = childNodes;
this.currentIndex = -1;
this.length = childNodes.length;
}
public next(): boolean {
this.currentIndex++;
if (this.currentIndex < this.length) {
this.currentElement = this.childNodes[this.currentIndex];
return true;
} else {
this.currentElement = undefined;
return false;
}
}
}

View File

@ -33,8 +33,8 @@ const defaultOptions: CircuitStartOptions = {
configureSignalR: (_) => { },
logLevel: LogLevel.Warning,
reconnectionOptions: {
maxRetries: 5,
retryIntervalMilliseconds: 3000,
maxRetries: 8,
retryIntervalMilliseconds: 20000,
dialogId: 'components-reconnect-modal',
},
};

View File

@ -12,9 +12,12 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
reloadParagraph: HTMLParagraphElement;
constructor(dialogId: string, private readonly document: Document, private readonly logger: Logger) {
loader: HTMLDivElement;
constructor(dialogId: string, private readonly maxRetries: number, private readonly document: Document, private readonly logger: Logger) {
this.modal = this.document.createElement('div');
this.modal.id = dialogId;
this.maxRetries = maxRetries;
const modalStyles = [
'position: fixed',
@ -37,6 +40,9 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
this.message = this.modal.querySelector('h5')!;
this.button = this.modal.querySelector('button')!;
this.reloadParagraph = this.modal.querySelector('p')!;
this.loader = this.getLoader();
this.message.after(this.loader);
this.button.addEventListener('click', async () => {
this.show();
@ -65,6 +71,7 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
this.document.body.appendChild(this.modal);
}
this.modal.style.display = 'block';
this.loader.style.display = 'inline-block';
this.button.style.display = 'none';
this.reloadParagraph.style.display = 'none';
this.message.textContent = 'Attempting to reconnect to the server...';
@ -78,6 +85,10 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
}, 0);
}
update(currentAttempt: number): void {
this.message.textContent = `Attempting to reconnect to the server: ${currentAttempt} of ${this.maxRetries}`;
}
hide(): void {
this.modal.style.display = 'none';
}
@ -85,6 +96,7 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
failed(): void {
this.button.style.display = 'block';
this.reloadParagraph.style.display = 'none';
this.loader.style.display = 'none';
this.message.innerHTML = 'Reconnection failed. Try <a href>reloading</a> the page if you\'re unable to reconnect.';
this.message.querySelector('a')!.addEventListener('click', () => location.reload());
}
@ -92,7 +104,32 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
rejected(): void {
this.button.style.display = 'none';
this.reloadParagraph.style.display = 'none';
this.loader.style.display = 'none';
this.message.innerHTML = 'Could not reconnect to the server. <a href>Reload</a> the page to restore functionality.';
this.message.querySelector('a')!.addEventListener('click', () => location.reload());
}
private getLoader(): HTMLDivElement {
const loader = this.document.createElement('div');
const loaderStyles = [
'border: 0.3em solid #f3f3f3',
'border-top: 0.3em solid #3498db',
'border-radius: 50%',
'width: 2em',
'height: 2em',
'display: inline-block'
];
loader.style.cssText = loaderStyles.join(';');
loader.animate([
{ transform: 'rotate(0deg)' },
{ transform: 'rotate(360deg)' }
], {
duration: 2000,
iterations: Infinity
});
return loader;
}
}

View File

@ -20,8 +20,8 @@ export class DefaultReconnectionHandler implements ReconnectionHandler {
if (!this._reconnectionDisplay) {
const modal = document.getElementById(options.dialogId);
this._reconnectionDisplay = modal
? new UserSpecifiedDisplay(modal)
: new DefaultReconnectDisplay(options.dialogId, document, this._logger);
? new UserSpecifiedDisplay(modal, options.maxRetries, document)
: new DefaultReconnectDisplay(options.dialogId, options.maxRetries, document, this._logger);
}
if (!this._currentReconnectionProcess) {
@ -38,6 +38,8 @@ export class DefaultReconnectionHandler implements ReconnectionHandler {
};
class ReconnectionProcess {
static readonly MaximumFirstRetryInterval = 3000;
readonly reconnectDisplay: ReconnectDisplay;
isDisposed = false;
@ -54,7 +56,13 @@ class ReconnectionProcess {
async attemptPeriodicReconnection(options: ReconnectionOptions) {
for (let i = 0; i < options.maxRetries; i++) {
await this.delay(options.retryIntervalMilliseconds);
this.reconnectDisplay.update(i + 1);
const delayDuration = i == 0 && options.retryIntervalMilliseconds > ReconnectionProcess.MaximumFirstRetryInterval
? ReconnectionProcess.MaximumFirstRetryInterval
: options.retryIntervalMilliseconds;
await this.delay(delayDuration);
if (this.isDisposed) {
break;
}

View File

@ -1,5 +1,6 @@
export interface ReconnectDisplay {
show(): void;
update(currentAttempt: number): void;
hide(): void;
failed(): void;
rejected(): void;

View File

@ -8,7 +8,18 @@ export class UserSpecifiedDisplay implements ReconnectDisplay {
static readonly RejectedClassName = 'components-reconnect-rejected';
constructor(private dialog: HTMLElement) {
static readonly MaxRetriesId = 'components-reconnect-max-retries';
static readonly CurrentAttemptId = 'components-reconnect-current-attempt';
constructor(private dialog: HTMLElement, private readonly maxRetries: number, private readonly document: Document) {
this.document = document;
const maxRetriesElement = this.document.getElementById(UserSpecifiedDisplay.MaxRetriesId);
if (maxRetriesElement) {
maxRetriesElement.innerText = this.maxRetries.toString();
}
}
show(): void {
@ -16,6 +27,14 @@ export class UserSpecifiedDisplay implements ReconnectDisplay {
this.dialog.classList.add(UserSpecifiedDisplay.ShowClassName);
}
update(currentAttempt: number): void {
const currentAttemptElement = this.document.getElementById(UserSpecifiedDisplay.CurrentAttemptId);
if (currentAttemptElement) {
currentAttemptElement.innerText = currentAttempt.toString();
}
}
hide(): void {
this.removeClasses();
this.dialog.classList.add(UserSpecifiedDisplay.HideClassName);

View File

@ -0,0 +1,51 @@
import { LogicalElement, toLogicalRootCommentElement } from '../Rendering/LogicalElements';
import { WebAssemblyComponentDescriptor } from '../Services/ComponentDescriptorDiscovery';
export class WebAssemblyComponentAttacher {
public preregisteredComponents: WebAssemblyComponentDescriptor[];
private componentsById: { [index: number]: WebAssemblyComponentDescriptor };
public constructor(components: WebAssemblyComponentDescriptor[]) {
this.preregisteredComponents = components;
const componentsById = {};
for (let index = 0; index < components.length; index++) {
const component = components[index];
componentsById[component.id] = component;
}
this.componentsById = componentsById;
}
public resolveRegisteredElement(id: string): LogicalElement | undefined {
const parsedId = Number.parseInt(id);
if (!Number.isNaN(parsedId)) {
return toLogicalRootCommentElement(this.componentsById[parsedId].start as Comment, this.componentsById[parsedId].end as Comment);
} else {
return undefined;
}
}
public getParameterValues(id: number): string | undefined {
return this.componentsById[id].parameterValues;
}
public getParameterDefinitions(id: number): string | undefined {
return this.componentsById[id].parameterDefinitions;
}
public getTypeName(id: number): string {
return this.componentsById[id].typeName;
}
public getAssembly(id: number): string {
return this.componentsById[id].assembly;
}
public getId(index: number): number {
return this.preregisteredComponents[index].id;
}
public getCount(): number {
return this.preregisteredComponents.length;
}
}

View File

@ -0,0 +1,354 @@
export function discoverComponents(document: Document, type: 'webassembly' | 'server'): ServerComponentDescriptor[] | WebAssemblyComponentDescriptor[] {
switch (type){
case 'webassembly':
return discoverWebAssemblyComponents(document);
case 'server':
return discoverServerComponents(document);
}
}
function discoverServerComponents(document: Document): ServerComponentDescriptor[] {
const componentComments = resolveComponentComments(document, 'server') as ServerComponentComment[];
const discoveredComponents: ServerComponentDescriptor[] = [];
for (let i = 0; i < componentComments.length; i++) {
const componentComment = componentComments[i];
const entry = new ServerComponentDescriptor(
componentComment.type,
componentComment.start,
componentComment.end,
componentComment.sequence,
componentComment.descriptor,
);
discoveredComponents.push(entry);
}
return discoveredComponents.sort((a, b): number => a.sequence - b.sequence);
}
function discoverWebAssemblyComponents(document: Document): WebAssemblyComponentDescriptor[] {
const componentComments = resolveComponentComments(document, 'webassembly') as WebAssemblyComponentDescriptor[];
const discoveredComponents: WebAssemblyComponentDescriptor[] = [];
for (let i = 0; i < componentComments.length; i++) {
const componentComment = componentComments[i];
const entry = new WebAssemblyComponentDescriptor(
componentComment.type,
componentComment.start,
componentComment.end,
componentComment.assembly,
componentComment.typeName,
componentComment.parameterDefinitions,
componentComment.parameterValues,
);
discoveredComponents.push(entry);
}
return discoveredComponents.sort((a, b): number => a.id - b.id);
}
interface ComponentComment {
type: 'server' | 'webassembly';
prerenderId?: string;
}
interface ServerComponentComment {
type: 'server';
sequence: number;
descriptor: string;
start: Node;
end?: Node;
prerenderId?: string;
}
interface WebAssemblyComponentComment {
type: 'webassembly';
typeName: string;
assembly: string;
parameterDefinitions?: string;
parameterValues?: string;
prerenderId?: string;
start: Node;
end?: Node;
}
function resolveComponentComments(node: Node, type: 'webassembly' | 'server'): ComponentComment[] {
if (!node.hasChildNodes()) {
return [];
}
const result: ComponentComment[] = [];
const childNodeIterator = new ComponentCommentIterator(node.childNodes);
while (childNodeIterator.next() && childNodeIterator.currentElement) {
const componentComment = getComponentComment(childNodeIterator, type);
if (componentComment) {
result.push(componentComment);
} else {
const childResults = resolveComponentComments(childNodeIterator.currentElement, type);
for (let j = 0; j < childResults.length; j++) {
const childResult = childResults[j];
result.push(childResult);
}
}
}
return result;
}
const blazorCommentRegularExpression = /\W*Blazor:[^{]*(?<descriptor>.*)$/;
function getComponentComment(commentNodeIterator: ComponentCommentIterator, type: 'webassembly' | 'server'): ComponentComment | undefined {
const candidateStart = commentNodeIterator.currentElement;
if (!candidateStart || candidateStart.nodeType !== Node.COMMENT_NODE) {
return;
}
if (candidateStart.textContent) {
const componentStartComment = new RegExp(blazorCommentRegularExpression);
const definition = componentStartComment.exec(candidateStart.textContent);
const json = definition && definition.groups && definition.groups['descriptor'];
if (json) {
try {
const componentComment = parseCommentPayload(json);
switch (type) {
case 'webassembly':
return createWebAssemblyComponentComment(componentComment as WebAssemblyComponentComment, candidateStart, commentNodeIterator);
case 'server':
return createServerComponentComment(componentComment as ServerComponentComment, candidateStart, commentNodeIterator);
}
} catch (error) {
throw new Error(`Found malformed component comment at ${candidateStart.textContent}`);
}
} else {
return;
}
}
}
function parseCommentPayload(json: string): ComponentComment {
const payload = JSON.parse(json) as ComponentComment;
const { type } = payload;
if (type !== 'server' && type !== 'webassembly') {
throw new Error(`Invalid component type '${type}'.`);
}
return payload;
}
function createServerComponentComment(payload: ServerComponentComment, start: Node, iterator: ComponentCommentIterator): ServerComponentComment | undefined {
const { type, descriptor, sequence, prerenderId } = payload;
if (type !== 'server') {
return undefined;
}
if (!descriptor) {
throw new Error('descriptor must be defined when using a descriptor.');
}
if (sequence === undefined) {
throw new Error('sequence must be defined when using a descriptor.');
}
if (!Number.isInteger(sequence)) {
throw new Error(`Error parsing the sequence '${sequence}' for component '${JSON.stringify(payload)}'`);
}
if (!prerenderId) {
return {
type,
sequence: sequence,
descriptor,
start,
};
} else {
const end = getComponentEndComment(prerenderId, iterator);
if (!end) {
throw new Error(`Could not find an end component comment for '${start}'`);
}
return {
type,
sequence,
descriptor,
start,
prerenderId,
end,
};
}
}
function createWebAssemblyComponentComment(payload: WebAssemblyComponentComment, start: Node, iterator: ComponentCommentIterator): WebAssemblyComponentComment | undefined {
const { type, assembly, typeName, parameterDefinitions, parameterValues, prerenderId } = payload;
if (type !== 'webassembly') {
return undefined;
}
if (!assembly) {
throw new Error('assembly must be defined when using a descriptor.');
}
if (!typeName) {
throw new Error('typeName must be defined when using a descriptor.');
}
if (!prerenderId) {
return {
type,
assembly,
typeName,
// Parameter definitions and values come Base64 encoded from the server, since they contain random data and can make the
// comment invalid. We could unencode them in .NET Code, but that would be slower to do and we can leverage the fact that
// JS provides a native function that will be much faster and that we are doing this work while we are fetching
// blazor.boot.json
parameterDefinitions: parameterDefinitions && atob(parameterDefinitions),
parameterValues: parameterValues && atob(parameterValues),
start,
};
} else {
const end = getComponentEndComment(prerenderId, iterator);
if (!end) {
throw new Error(`Could not find an end component comment for '${start}'`);
}
return {
type,
assembly,
typeName,
// Same comment as above.
parameterDefinitions: parameterDefinitions && atob(parameterDefinitions),
parameterValues: parameterValues && atob(parameterValues),
start,
prerenderId,
end,
};
}
}
function getComponentEndComment(prerenderedId: string, iterator: ComponentCommentIterator): ChildNode | undefined {
while (iterator.next() && iterator.currentElement) {
const node = iterator.currentElement;
if (node.nodeType !== Node.COMMENT_NODE) {
continue;
}
if (!node.textContent) {
continue;
}
const definition = new RegExp(blazorCommentRegularExpression).exec(node.textContent);
const json = definition && definition[1];
if (!json) {
continue;
}
validateEndComponentPayload(json, prerenderedId);
return node;
}
return undefined;
}
function validateEndComponentPayload(json: string, prerenderedId: string): void {
const payload = JSON.parse(json) as ComponentComment;
if (Object.keys(payload).length !== 1) {
throw new Error(`Invalid end of component comment: '${json}'`);
}
const prerenderedEndId = payload.prerenderId;
if (!prerenderedEndId) {
throw new Error(`End of component comment must have a value for the prerendered property: '${json}'`);
}
if (prerenderedEndId !== prerenderedId) {
throw new Error(`End of component comment prerendered property must match the start comment prerender id: '${prerenderedId}', '${prerenderedEndId}'`);
}
}
class ComponentCommentIterator {
private childNodes: NodeListOf<ChildNode>;
private currentIndex: number;
private length: number;
public currentElement: ChildNode | undefined;
public constructor(childNodes: NodeListOf<ChildNode>) {
this.childNodes = childNodes;
this.currentIndex = -1;
this.length = childNodes.length;
}
public next(): boolean {
this.currentIndex++;
if (this.currentIndex < this.length) {
this.currentElement = this.childNodes[this.currentIndex];
return true;
} else {
this.currentElement = undefined;
return false;
}
}
}
interface ServerComponentMarker {
type: string;
sequence: number;
descriptor: string;
}
export class ServerComponentDescriptor {
public type: string;
public start: Node;
public end?: Node;
public sequence: number;
public descriptor: string;
public constructor(type: string, start: Node, end: Node | undefined, sequence: number, descriptor: string) {
this.type = type;
this.start = start;
this.end = end;
this.sequence = sequence;
this.descriptor = descriptor;
}
public toRecord(): ServerComponentMarker {
const result = { type: this.type, sequence: this.sequence, descriptor: this.descriptor };
return result;
}
}
export class WebAssemblyComponentDescriptor {
private static globalId = 1;
public type: 'webassembly';
public typeName: string;
public assembly: string;
public parameterDefinitions?: string;
public parameterValues?: string;
public id: number;
public start: Node;
public end?: Node;
public constructor(type: 'webassembly', start: Node, end: Node | undefined, assembly: string, typeName: string, parameterDefinitions?: string, parameterValues?: string) {
this.id = WebAssemblyComponentDescriptor.globalId++;
this.type = type;
this.assembly = assembly;
this.typeName = typeName;
this.parameterDefinitions = parameterDefinitions;
this.parameterValues = parameterValues;
this.start = start;
this.end = end;
}
}

View File

@ -57,15 +57,16 @@ function init(dotNetHelper: any, spacerBefore: HTMLElement, spacerAfter: HTMLEle
return;
}
const spacerSeparation = spacerAfter.offsetTop - (spacerBefore.offsetTop + spacerBefore.offsetHeight);
const containerSize = entry.rootBounds?.height;
if (entry.target === spacerBefore) {
dotNetHelper.invokeMethodAsync('OnSpacerBeforeVisible', entry.intersectionRect.top - entry.boundingClientRect.top, containerSize);
dotNetHelper.invokeMethodAsync('OnSpacerBeforeVisible', entry.intersectionRect.top - entry.boundingClientRect.top, spacerSeparation, containerSize);
} else if (entry.target === spacerAfter && spacerAfter.offsetHeight > 0) {
// When we first start up, both the "before" and "after" spacers will be visible, but it's only relevant to raise a
// single event to load the initial data. To avoid raising two events, skip the one for the "after" spacer if we know
// it's meaningless to talk about any overlap into it.
dotNetHelper.invokeMethodAsync('OnSpacerAfterVisible', entry.boundingClientRect.bottom - entry.intersectionRect.bottom, containerSize);
dotNetHelper.invokeMethodAsync('OnSpacerAfterVisible', entry.boundingClientRect.bottom - entry.intersectionRect.bottom, spacerSeparation, containerSize);
}
});
}

View File

@ -3,10 +3,18 @@ import { JSDOM } from 'jsdom';
import { NullLogger } from '../src/Platform/Logging/Loggers';
describe('DefaultReconnectDisplay', () => {
let testDocument: Document;
beforeEach(() => {
const window = new JSDOM().window;
//JSDOM does not support animate function so we need to mock it
window.HTMLDivElement.prototype.animate = jest.fn();
testDocument = window.document;
})
it ('adds element to the body on show', () => {
const testDocument = new JSDOM().window.document;
const display = new DefaultReconnectDisplay('test-dialog-id', testDocument, NullLogger.instance);
const display = new DefaultReconnectDisplay('test-dialog-id', 6, testDocument, NullLogger.instance);
display.show();
@ -16,6 +24,7 @@ describe('DefaultReconnectDisplay', () => {
expect(element!.style.display).toBe('block');
expect(element!.style.visibility).toBe('hidden');
expect(display.loader.style.display).toBe('inline-block');
expect(display.message.textContent).toBe('Attempting to reconnect to the server...');
expect(display.button.style.display).toBe('none');
@ -27,8 +36,7 @@ describe('DefaultReconnectDisplay', () => {
});
it ('does not add element to the body multiple times', () => {
const testDocument = new JSDOM().window.document;
const display = new DefaultReconnectDisplay('test-dialog-id', testDocument, NullLogger.instance);
const display = new DefaultReconnectDisplay('test-dialog-id', 6, testDocument, NullLogger.instance);
display.show();
display.show();
@ -37,8 +45,7 @@ describe('DefaultReconnectDisplay', () => {
});
it ('hides element', () => {
const testDocument = new JSDOM().window.document;
const display = new DefaultReconnectDisplay('test-dialog-id', testDocument, NullLogger.instance);
const display = new DefaultReconnectDisplay('test-dialog-id', 6, testDocument, NullLogger.instance);
display.hide();
@ -46,8 +53,7 @@ describe('DefaultReconnectDisplay', () => {
});
it ('updates message on fail', () => {
const testDocument = new JSDOM().window.document;
const display = new DefaultReconnectDisplay('test-dialog-id', testDocument, NullLogger.instance);
const display = new DefaultReconnectDisplay('test-dialog-id', 6, testDocument, NullLogger.instance);
display.show();
display.failed();
@ -55,11 +61,11 @@ describe('DefaultReconnectDisplay', () => {
expect(display.modal.style.display).toBe('block');
expect(display.message.innerHTML).toBe('Reconnection failed. Try <a href=\"\">reloading</a> the page if you\'re unable to reconnect.');
expect(display.button.style.display).toBe('block');
expect(display.loader.style.display).toBe('none');
});
it ('updates message on refused', () => {
const testDocument = new JSDOM().window.document;
const display = new DefaultReconnectDisplay('test-dialog-id', testDocument, NullLogger.instance);
const display = new DefaultReconnectDisplay('test-dialog-id', 6, testDocument, NullLogger.instance);
display.show();
display.rejected();
@ -67,6 +73,18 @@ describe('DefaultReconnectDisplay', () => {
expect(display.modal.style.display).toBe('block');
expect(display.message.innerHTML).toBe('Could not reconnect to the server. <a href=\"\">Reload</a> the page to restore functionality.');
expect(display.button.style.display).toBe('none');
expect(display.loader.style.display).toBe('none');
});
it('update message with current attempt', () => {
const maxRetires = 6;
const display = new DefaultReconnectDisplay('test-dialog-id', maxRetires, testDocument, NullLogger.instance);
display.show();
for (let index = 0; index < maxRetires; index++) {
display.update(index);
expect(display.message.innerHTML).toBe(`Attempting to reconnect to the server: ${index++} of ${maxRetires}`);
}
})
});

View File

@ -75,6 +75,23 @@ describe('DefaultReconnectionHandler', () => {
expect(testDisplay.failed).toHaveBeenCalled();
expect(reconnect).toHaveBeenCalledTimes(2);
});
it('invokes update on each attempt', async () => {
const testDisplay = createTestDisplay();
const reconnect = jest.fn().mockRejectedValue(null);
const handler = new DefaultReconnectionHandler(NullLogger.instance, testDisplay, reconnect);
const maxRetries = 6;
handler.onConnectionDown({
maxRetries: maxRetries,
retryIntervalMilliseconds: 5,
dialogId: 'ignored'
});
await delay(500);
expect(testDisplay.update).toHaveBeenCalledTimes(maxRetries);
})
});
function attachUserSpecifiedUI(options: ReconnectionOptions): Element {
@ -92,6 +109,7 @@ function delay(durationMilliseconds: number) {
function createTestDisplay(): ReconnectDisplay {
return {
show: jest.fn(),
update: jest.fn(),
hide: jest.fn(),
failed: jest.fn(),
rejected: jest.fn()

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Linq.Expressions;
namespace Microsoft.AspNetCore.Components.Forms
@ -13,6 +12,8 @@ namespace Microsoft.AspNetCore.Components.Forms
/// </summary>
public static class EditContextFieldClassExtensions
{
private readonly static object FieldCssClassProviderKey = new object();
/// <summary>
/// Gets a string that indicates the status of the specified field as a CSS class. This will include
/// some combination of "modified", "valid", or "invalid", depending on the status of the field.
@ -24,23 +25,34 @@ namespace Microsoft.AspNetCore.Components.Forms
=> FieldCssClass(editContext, FieldIdentifier.Create(accessor));
/// <summary>
/// Gets a string that indicates the status of the specified field as a CSS class. This will include
/// some combination of "modified", "valid", or "invalid", depending on the status of the field.
/// Gets a string that indicates the status of the specified field as a CSS class.
/// </summary>
/// <param name="editContext">The <see cref="EditContext"/>.</param>
/// <param name="fieldIdentifier">An identifier for the field.</param>
/// <returns>A string that indicates the status of the field.</returns>
public static string FieldCssClass(this EditContext editContext, in FieldIdentifier fieldIdentifier)
{
var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();
if (editContext.IsModified(fieldIdentifier))
var provider = editContext.Properties.TryGetValue(FieldCssClassProviderKey, out var customProvider)
? (FieldCssClassProvider)customProvider
: FieldCssClassProvider.Instance;
return provider.GetFieldCssClass(editContext, fieldIdentifier);
}
/// <summary>
/// Associates the supplied <see cref="FieldCssClassProvider"/> with the supplied <see cref="EditContext"/>.
/// This customizes the field CSS class names used within the <see cref="EditContext"/>.
/// </summary>
/// <param name="editContext">The <see cref="EditContext"/>.</param>
/// <param name="fieldCssClassProvider">The <see cref="FieldCssClassProvider"/>.</param>
public static void SetFieldCssClassProvider(this EditContext editContext, FieldCssClassProvider fieldCssClassProvider)
{
if (fieldCssClassProvider is null)
{
return isValid ? "modified valid" : "modified invalid";
}
else
{
return isValid ? "valid" : "invalid";
throw new ArgumentNullException(nameof(fieldCssClassProvider));
}
editContext.Properties[FieldCssClassProviderKey] = fieldCssClassProvider;
}
}
}

View File

@ -0,0 +1,35 @@
// 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;
namespace Microsoft.AspNetCore.Components.Forms
{
/// <summary>
/// Supplies CSS class names for form fields to represent their validation state or other
/// state information from an <see cref="EditContext"/>.
/// </summary>
public class FieldCssClassProvider
{
internal readonly static FieldCssClassProvider Instance = new FieldCssClassProvider();
/// <summary>
/// Gets a string that indicates the status of the specified field as a CSS class.
/// </summary>
/// <param name="editContext">The <see cref="EditContext"/>.</param>
/// <param name="fieldIdentifier">The <see cref="FieldIdentifier"/>.</param>
/// <returns>A CSS class name string.</returns>
public virtual string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier)
{
var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();
if (editContext.IsModified(fieldIdentifier))
{
return isValid ? "modified valid" : "modified invalid";
}
else
{
return isValid ? "valid" : "invalid";
}
}
}
}

View File

@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
{
internal interface IVirtualizeJsCallbacks
{
void OnBeforeSpacerVisible(float spacerSize, float containerSize);
void OnAfterSpacerVisible(float spacerSize, float containerSize);
void OnBeforeSpacerVisible(float spacerSize, float spacerSeparation, float containerSize);
void OnAfterSpacerVisible(float spacerSize, float spacerSeparation, float containerSize);
}
}

View File

@ -13,13 +13,24 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
/// </summary>
public int Index { get; }
/// <summary>
/// The size of the placeholder in pixels.
/// <para>
/// For virtualized components with vertical scrolling, this would be the height of the placeholder in pixels.
/// For virtualized components with horizontal scrolling, this would be the width of the placeholder in pixels.
/// </para>
/// </summary>
public float Size { get; }
/// <summary>
/// Constructs a new <see cref="PlaceholderContext"/> instance.
/// </summary>
/// <param name="index">The item index of the placeholder.</param>
public PlaceholderContext(int index)
/// <param name="size">The size of the placeholder in pixels.</param>
public PlaceholderContext(int index, float size = 0f)
{
Index = index;
Size = size;
}
}
}

View File

@ -31,6 +31,12 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
private int _loadedItemsStartIndex;
private int _lastRenderedItemCount;
private int _lastRenderedPlaceholderCount;
private float _itemSize;
private IEnumerable<TItem>? _loadedItems;
private CancellationTokenSource? _refreshCts;
@ -65,10 +71,10 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
public RenderFragment<PlaceholderContext>? Placeholder { get; set; }
/// <summary>
/// Gets the size of each item in pixels.
/// Gets the size of each item in pixels. Defaults to 50px.
/// </summary>
[Parameter]
public float ItemSize { get; set; }
public float ItemSize { get; set; } = 50f;
/// <summary>
/// Gets or sets the function providing items to the list.
@ -88,7 +94,12 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
if (ItemSize <= 0)
{
throw new InvalidOperationException(
$"{GetType()} requires a positive value for parameter '{nameof(ItemSize)}' to perform virtualization.");
$"{GetType()} requires a positive value for parameter '{nameof(ItemSize)}'.");
}
if (_itemSize <= 0)
{
_itemSize = ItemSize;
}
if (ItemsProvider != null)
@ -154,11 +165,13 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
{
// This is a rare case where it's valid for the sequence number to be programmatically incremented.
// This is only true because we know for certain that no other content will be alongside it.
builder.AddContent(renderIndex, _placeholder, new PlaceholderContext(renderIndex));
builder.AddContent(renderIndex, _placeholder, new PlaceholderContext(renderIndex, _itemSize));
}
builder.CloseRegion();
_lastRenderedItemCount = 0;
// Render the loaded items.
if (_loadedItems != null && _itemTemplate != null)
{
@ -171,18 +184,22 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
foreach (var item in itemsToShow)
{
_itemTemplate(item)(builder);
renderIndex++;
_lastRenderedItemCount++;
}
renderIndex += _lastRenderedItemCount;
builder.CloseRegion();
}
_lastRenderedPlaceholderCount = Math.Max(0, lastItemIndex - _itemsBefore - _lastRenderedItemCount);
builder.OpenRegion(5);
// Render the placeholders after the loaded items.
for (; renderIndex < lastItemIndex; renderIndex++)
{
builder.AddContent(renderIndex, _placeholder, new PlaceholderContext(renderIndex));
builder.AddContent(renderIndex, _placeholder, new PlaceholderContext(renderIndex, _itemSize));
}
builder.CloseRegion();
@ -197,28 +214,45 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
}
private string GetSpacerStyle(int itemsInSpacer)
=> $"height: {itemsInSpacer * ItemSize}px;";
=> $"height: {itemsInSpacer * _itemSize}px;";
void IVirtualizeJsCallbacks.OnBeforeSpacerVisible(float spacerSize, float containerSize)
void IVirtualizeJsCallbacks.OnBeforeSpacerVisible(float spacerSize, float spacerSeparation, float containerSize)
{
CalcualteItemDistribution(spacerSize, containerSize, out var itemsBefore, out var visibleItemCapacity);
CalcualteItemDistribution(spacerSize, spacerSeparation, containerSize, out var itemsBefore, out var visibleItemCapacity);
UpdateItemDistribution(itemsBefore, visibleItemCapacity);
}
void IVirtualizeJsCallbacks.OnAfterSpacerVisible(float spacerSize, float containerSize)
void IVirtualizeJsCallbacks.OnAfterSpacerVisible(float spacerSize, float spacerSeparation, float containerSize)
{
CalcualteItemDistribution(spacerSize, containerSize, out var itemsAfter, out var visibleItemCapacity);
CalcualteItemDistribution(spacerSize, spacerSeparation, containerSize, out var itemsAfter, out var visibleItemCapacity);
var itemsBefore = Math.Max(0, _itemCount - itemsAfter - visibleItemCapacity);
UpdateItemDistribution(itemsBefore, visibleItemCapacity);
}
private void CalcualteItemDistribution(float spacerSize, float containerSize, out int itemsInSpacer, out int visibleItemCapacity)
private void CalcualteItemDistribution(
float spacerSize,
float spacerSeparation,
float containerSize,
out int itemsInSpacer,
out int visibleItemCapacity)
{
itemsInSpacer = Math.Max(0, (int)Math.Floor(spacerSize / ItemSize) - 1);
visibleItemCapacity = (int)Math.Ceiling(containerSize / ItemSize) + 2;
if (_lastRenderedItemCount > 0)
{
_itemSize = (spacerSeparation - (_lastRenderedPlaceholderCount * _itemSize)) / _lastRenderedItemCount;
}
if (_itemSize <= 0)
{
// At this point, something unusual has occurred, likely due to misuse of this component.
// Reset the calculated item size to the user-provided item size.
_itemSize = ItemSize;
}
itemsInSpacer = Math.Max(0, (int)Math.Floor(spacerSize / _itemSize) - 1);
visibleItemCapacity = (int)Math.Ceiling(containerSize / _itemSize) + 2;
}
private void UpdateItemDistribution(int itemsBefore, int visibleItemCapacity)
@ -285,7 +319,7 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
private RenderFragment DefaultPlaceholder(PlaceholderContext context) => (builder) =>
{
builder.OpenElement(0, "div");
builder.AddAttribute(1, "style", $"height: {ItemSize}px;");
builder.AddAttribute(1, "style", $"height: {_itemSize}px;");
builder.CloseElement();
};

View File

@ -30,15 +30,15 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
}
[JSInvokable]
public void OnSpacerBeforeVisible(float spacerSize, float containerSize)
public void OnSpacerBeforeVisible(float spacerSize, float spacerSeparation, float containerSize)
{
_owner.OnBeforeSpacerVisible(spacerSize, containerSize);
_owner.OnBeforeSpacerVisible(spacerSize, spacerSeparation, containerSize);
}
[JSInvokable]
public void OnSpacerAfterVisible(float spacerSize, float containerSize)
public void OnSpacerAfterVisible(float spacerSize, float spacerSeparation, float containerSize)
{
_owner.OnAfterSpacerVisible(spacerSize, containerSize);
_owner.OnAfterSpacerVisible(spacerSize, spacerSeparation, containerSize);
}
public async ValueTask DisposeAsync()

View File

@ -97,7 +97,7 @@ namespace Microsoft.AspNetCore.Components.Virtualization
Assert.NotNull(renderedVirtualize);
// Simulate a JS spacer callback.
((IVirtualizeJsCallbacks)renderedVirtualize).OnAfterSpacerVisible(10f, 100f);
((IVirtualizeJsCallbacks)renderedVirtualize).OnAfterSpacerVisible(10f, 50f, 100f);
// Validate that the exception is dispatched through the renderer.
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await testRenderer.RenderRootComponentAsync(componentId));

View File

@ -1,6 +1,5 @@
import * as Msal from 'msal';
import { StringDict } from 'msal/lib-commonjs/MsalTypes';
import { ClientAuthErrorMessage } from 'msal/lib-commonjs/error/ClientAuthError';
import * as Msal from '@azure/msal-browser';
import { StringDict } from '@azure/msal-common';
interface AccessTokenRequestOptions {
scopes: string[];
@ -52,34 +51,53 @@ interface AuthorizeServiceConfiguration extends Msal.Configuration {
}
class MsalAuthorizeService implements AuthorizeService {
readonly _msalApplication: Msal.UserAgentApplication;
readonly _callbackPromise: Promise<AuthenticationResult>;
private readonly _msalApplication: Msal.PublicClientApplication;
private _account: Msal.AccountInfo | undefined;
private _redirectCallback: Promise<AuthenticationResult | null> | undefined;
constructor(private readonly _settings: AuthorizeServiceConfiguration) {
if (this._settings.auth?.knownAuthorities?.length == 0) {
this._settings.auth.knownAuthorities = [new URL(this._settings.auth.authority!).hostname]
}
this._msalApplication = new Msal.PublicClientApplication(this._settings);
}
// It is important that we capture the callback-url here as msal will remove the auth parameters
// from the url as soon as it gets initialized.
const callbackUrl = location.href;
this._msalApplication = new Msal.UserAgentApplication(this._settings);
getAccount() {
if (this._account) {
return this._account;
}
// This promise will only resolve in callback-paths, which is where we check it.
this._callbackPromise = this.createCallbackResult(callbackUrl);
const accounts = this._msalApplication.getAllAccounts();
if (accounts && accounts.length) {
return accounts[0];
}
return null;
}
async getUser() {
const account = this._msalApplication.getAccount();
return account?.idTokenClaims;
const account = this.getAccount();
if (!account) {
return;
}
const silentRequest = {
redirectUri: this._settings.auth?.redirectUri,
account: account,
scopes: this._settings.defaultAccessTokenScopes
};
const response = await this._msalApplication.acquireTokenSilent(silentRequest);
return response.idTokenClaims;
}
async getAccessToken(request?: AccessTokenRequestOptions): Promise<AccessTokenResult> {
try {
const newToken = await this.getTokenCore(request?.scopes);
return {
status: AccessTokenResultStatus.Success,
token: newToken
};
} catch (e) {
return {
status: AccessTokenResultStatus.RequiresRedirect
@ -88,12 +106,18 @@ class MsalAuthorizeService implements AuthorizeService {
}
async getTokenCore(scopes?: string[]): Promise<AccessToken | undefined> {
const tokenScopes = {
redirectUri: this._settings.auth.redirectUri as string,
const account = this.getAccount();
if (!account) {
return;
}
const silentRequest = {
redirectUri: this._settings.auth?.redirectUri,
account: account,
scopes: scopes || this._settings.defaultAccessTokenScopes
};
const response = await this._msalApplication.acquireTokenSilent(tokenScopes);
const response = await this._msalApplication.acquireTokenSilent(silentRequest);
return {
value: response.accessToken,
grantedScopes: response.scopes,
@ -106,9 +130,10 @@ class MsalAuthorizeService implements AuthorizeService {
// Before we start any sign-in flow, clear out any previous state so that it doesn't pile up.
this.purgeState();
const request: Msal.AuthenticationParameters = {
redirectUri: this._settings.auth.redirectUri as string,
state: await this.saveState(state)
const request: Msal.AuthorizationUrlRequest = {
redirectUri: this._settings.auth?.redirectUri,
state: await this.saveState(state),
scopes: []
};
if (this._settings.defaultAccessTokenScopes && this._settings.defaultAccessTokenScopes.length > 0) {
@ -130,7 +155,16 @@ class MsalAuthorizeService implements AuthorizeService {
if (this._settings.defaultAccessTokenScopes?.length > 0) {
// This provisions the token as part of the sign-in flow eagerly so that is already in the cache
// when the app asks for it.
await this._msalApplication.acquireTokenSilent(request);
const account = this.getAccount();
if (!account) {
return this.error("No account to get tokens for.");
}
const silentRequest = {
redirectUri: request.redirectUri,
account: account,
scopes: request.scopes,
};
await this._msalApplication.acquireTokenSilent(silentRequest);
}
} catch (e) {
return this.error(e.errorMessage);
@ -142,33 +176,45 @@ class MsalAuthorizeService implements AuthorizeService {
}
}
async signInCore(request: Msal.AuthenticationParameters): Promise<Msal.AuthResponse | Msal.AuthError | undefined> {
if (this._settings.loginMode.toLowerCase() === "redirect") {
try {
this._msalApplication.loginRedirect(request);
} catch (e) {
return e;
}
async signInCore(request: Msal.AuthorizationUrlRequest): Promise<Msal.AuthenticationResult | Msal.AuthError | undefined> {
const loginMode = this._settings.loginMode.toLowerCase();
if (loginMode === 'redirect') {
return this.signInWithRedirect(request);
} else {
try {
return await this._msalApplication.loginPopup(request);
} catch (e) {
// If the user explicitly cancelled the pop-up, avoid performing a redirect.
if (this.isMsalError(e) && e.errorCode !== ClientAuthErrorMessage.userCancelledError.code) {
try {
this._msalApplication.loginRedirect(request);
} catch (e) {
return e;
}
} else {
return e;
}
return this.signInWithPopup(request);
}
}
private async signInWithRedirect(request: Msal.RedirectRequest) {
try {
return await this._msalApplication.loginRedirect(request);
} catch (e) {
return e;
}
}
private async signInWithPopup(request: Msal.PopupRequest) {
try {
return await this._msalApplication.loginPopup(request);
} catch (e) {
// If the user explicitly cancelled the pop-up, avoid performing a redirect.
if (this.isMsalError(e) && e.errorCode !== Msal.BrowserAuthErrorMessage.userCancelledError.code) {
this.signInWithRedirect(request);
} else {
return e;
}
}
}
completeSignIn() {
return this._callbackPromise;
async completeSignIn() {
// Make sure that the redirect handler has completed execution before
// completing sign in.
await this._redirectCallback;
const account = this.getAccount();
if (account) {
return this.success(account);
}
return this.operationCompleted();
}
async signOut(state: any) {
@ -241,7 +287,7 @@ class MsalAuthorizeService implements AuthorizeService {
// msal.js doesn't support the state parameter on logout flows, which forces us to shim our own logout state.
// The format then is different, as msal follows the pattern state=<<guid>>|<<user_state>> and our format
// simple uses <<base64urlIdentifier>>.
const appState = !isLogout ? this._msalApplication.getAccountState(state[0]) : state[0];
const appState = !isLogout ? this.getAccountState(state[0]) : state[0];
const stateKey = `${AuthenticationService._infrastructureKey}.AuthorizeService.${appState}`;
const stateString = sessionStorage.getItem(stateKey);
if (stateString) {
@ -262,37 +308,35 @@ class MsalAuthorizeService implements AuthorizeService {
}
}
private async createCallbackResult(callbackUrl: string): Promise<AuthenticationResult> {
// msal.js requires a callback to be registered during app initialization to handle redirect flows.
// To map that behavior to our API we register a callback early and store the result of that callback
// as a promise on an instance field to be able to serve the state back to the main app.
const promiseFactory = (resolve: (result: Msal.AuthResponse) => void, reject: (error: Msal.AuthError) => void): void => {
this._msalApplication.handleRedirectCallback(
authenticationResponse => {
resolve(authenticationResponse);
},
authenticationError => {
reject(authenticationError);
});
}
async initializeMsalHandler() {
this._redirectCallback = this._msalApplication.handleRedirectPromise().then(
(result: Msal.AuthenticationResult | null) => this.handleResult(result)
).catch((error: any) => {
if (this.isMsalError(error)) {
return this.error(error.errorMessage);
} else {
return this.error(error);
}
})
}
try {
// Evaluate the promise to capture any authentication errors
await new Promise<Msal.AuthResponse>(promiseFactory);
// See https://github.com/AzureAD/microsoft-authentication-library-for-js/wiki/FAQs#q6-how-to-avoid-page-reloads-when-acquiring-and-renewing-tokens-silently
if (window !== window.parent && !window.opener) {
return this.operationCompleted();
} else {
const state = await this.retrieveState(callbackUrl);
return this.success(state);
}
} catch (e) {
if (this.isMsalError(e)) {
return this.error(e.errorMessage);
} else {
return this.error(e);
private handleResult(result: Msal.AuthenticationResult | null) {
if (result != null) {
this._account = result.account;
return this.success(result.state);
} else {
return this.operationCompleted();
}
}
private getAccountState(state: string) {
if (state) {
const splitIndex = state.indexOf("|");
if (splitIndex > -1 && splitIndex + 1 < state.length) {
return state.substring(splitIndex + 1);
}
}
return state;
}
private isMsalError(resultOrError: any): resultOrError is Msal.AuthError {
@ -319,14 +363,15 @@ class MsalAuthorizeService implements AuthorizeService {
export class AuthenticationService {
static _infrastructureKey = 'Microsoft.Authentication.WebAssembly.Msal';
static _initialized = false;
static _initialized: Promise<void>;
static instance: MsalAuthorizeService;
public static async init(settings: AuthorizeServiceConfiguration) {
if (!AuthenticationService._initialized) {
AuthenticationService._initialized = true;
AuthenticationService.instance = new MsalAuthorizeService(settings);
AuthenticationService._initialized = AuthenticationService.instance.initializeMsalHandler();
}
return AuthenticationService._initialized;
}
public static getUser() {

View File

@ -13,6 +13,6 @@
"webpack-cli": "^3.3.10"
},
"dependencies": {
"msal": "^1.2.1"
"@azure/msal-browser": "^2.0.0"
}
}

View File

@ -2,6 +2,20 @@
# yarn lockfile v1
"@azure/msal-browser@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-2.0.0.tgz#09eb3ed2112bdcd11c751f1c0b9cec588b49b8c6"
integrity sha512-0L4XksaXmtl870bQTPxbHCkxMEMmSbsgkkVpb6bvXg8ngOLWnkxvV6tstj84JtQHcJPjNYkYY41jgBQxgC4/KQ==
dependencies:
"@azure/msal-common" "1.0.0"
"@azure/msal-common@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-1.0.0.tgz#421f4859e6cb68cfacb03bb2c6c873efdffc76f0"
integrity sha512-l/+1Z9kQWLAlMwJ/c3MGhy4ujtEAK/3CMUaUXHvjUIsQknLFRb9+b3id5YSuToPfAvdUkAQGDZiQXosv1I+eLA==
dependencies:
debug "^4.1.1"
"@webassemblyjs/ast@1.8.5":
version "1.8.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359"
@ -690,6 +704,13 @@ debug@^2.2.0, debug@^2.3.3:
dependencies:
ms "2.0.0"
debug@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
dependencies:
ms "^2.1.1"
decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@ -1667,12 +1688,10 @@ ms@2.0.0:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
msal@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/msal/-/msal-1.2.1.tgz#08133e37ab0b9741866c89a3fadc55aadb980723"
integrity sha512-Zo28eyRtT/Un+zcpMfPtTPD+eo/OqzsRER0k5dyk8Mje/K1oLlaEOAgZHlJs59Y2xyuVg8OrcKqSn/1MeNjZYw==
dependencies:
tslib "^1.9.3"
ms@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
nan@^2.12.1:
version "2.14.0"
@ -2485,7 +2504,7 @@ ts-loader@^6.2.1:
micromatch "^4.0.0"
semver "^6.0.0"
tslib@^1.9.0, tslib@^1.9.3:
tslib@^1.9.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
namespace Microsoft.Authentication.WebAssembly.Msal
{
@ -48,5 +49,10 @@ namespace Microsoft.Authentication.WebAssembly.Msal
/// Gets or sets whether or not to navigate to the login request url after a successful login.
/// </summary>
public bool NavigateToLoginRequestUrl { get; set; } = false;
/// <summary>
/// Gets or sets the set of known authority host names for the application.
/// </summary>
public IList<string> KnownAuthorities { get; set; } = new List<string>();
}
}

View File

@ -11,17 +11,26 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!-- Set this to false because assemblies should not reference this assembly directly, (except for tests, of course). -->
<IsProjectReferenceProvider>false</IsProjectReferenceProvider>
<!--
This project compiles against Microsoft.AspNetCore.App from the SDK.
This ensures that it's packaging output is correct and does not include local artifacts.
-->
<UseAspNetCoreSharedRuntime>true</UseAspNetCoreSharedRuntime>
<DoNotApplyWorkaroundsToMicrosoftAspNetCoreApp>true</DoNotApplyWorkaroundsToMicrosoftAspNetCoreApp>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNetCore" />
<Reference Include="Microsoft.AspNetCore.Diagnostics" />
<Reference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" />
<Reference Include="Microsoft.AspNetCore.Components.Server" />
<Reference Include="Microsoft.AspNetCore.ResponseCompression" />
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<ProjectReference
Include="$(RepoRoot)src\Framework\App.Runtime\src\Microsoft.AspNetCore.App.Runtime.csproj"
PrivateAssets="All"
ReferenceOutputAssembly="false"
SkipGetTargetFrameworkProperties="true" />
<Reference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" />
<Compile Include="$(SharedSourceRoot)CommandLineUtils\**\*.cs" />
<Reference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>
<!-- Pack settings -->
@ -36,19 +45,5 @@
<NuspecProperty Include="PackageThirdPartyNoticesFile=$(PackageThirdPartyNoticesFile)" />
</ItemGroup>
<Target Name="_FixupRuntimeConfig" BeforeTargets="_GenerateRuntimeConfigurationFilesInputCache">
<ItemGroup>
<_RuntimeFramework Include="@(RuntimeFramework)" />
<RuntimeFramework Remove="@(RuntimeFramework)" />
<RuntimeFramework Include="Microsoft.AspNetCore.App" FrameworkName="Microsoft.AspNetCore.App" Version="5.0.0-preview" />
</ItemGroup>
</Target>
<Target Name="_UndoRuntimeConfigWorkarounds" AfterTargets="GenerateBuildRuntimeConfigurationFiles">
<ItemGroup>
<RuntimeFramework Remove="@(RuntimeFramework)" />
<RuntimeFramework Include="@(_RuntimeFramework)" />
</ItemGroup>
</Target>
</Project>

View File

@ -16,12 +16,7 @@ namespace WebAssembly.JSInterop
// in driver.c in the Mono distribution
/// See: https://github.com/mono/mono/blob/90574987940959fe386008a850982ea18236a533/sdks/wasm/src/driver.c#L318-L319
// 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, [AllowNull] T0 arg0, [AllowNull] T1 arg1, [AllowNull] T2 arg2);
public static extern TRes InvokeJS<T0, T1, T2, TRes>(out string exception, ref JSCallInfo callInfo, [AllowNull] T0 arg0, [AllowNull] T1 arg1, [AllowNull] T2 arg2);
}
}

View File

@ -0,0 +1,27 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.InteropServices;
using Microsoft.JSInterop;
namespace WebAssembly.JSInterop
{
[StructLayout(LayoutKind.Explicit, Pack = 4)]
internal struct JSCallInfo
{
[FieldOffset(0)]
public string FunctionIdentifier;
[FieldOffset(4)]
public JSCallResultType ResultType;
[FieldOffset(8)]
public string MarshalledCallArgsJson;
[FieldOffset(12)]
public long MarshalledCallAsyncHandle;
[FieldOffset(20)]
public long TargetInstanceId;
}
}

View File

@ -11,22 +11,40 @@ namespace Microsoft.JSInterop.WebAssembly
/// Provides methods for invoking JavaScript functions for applications running
/// on the Mono WebAssembly runtime.
/// </summary>
public abstract class WebAssemblyJSRuntime : JSInProcessRuntime
public abstract class WebAssemblyJSRuntime : JSInProcessRuntime, IJSUnmarshalledRuntime
{
/// <inheritdoc />
protected override string InvokeJS(string identifier, string argsJson)
protected override string InvokeJS(string identifier, string argsJson, JSCallResultType resultType, long targetInstanceId)
{
var noAsyncHandle = default(long);
var result = InternalCalls.InvokeJSMarshalled(out var exception, ref noAsyncHandle, identifier, argsJson);
var callInfo = new JSCallInfo
{
FunctionIdentifier = identifier,
TargetInstanceId = targetInstanceId,
ResultType = resultType,
MarshalledCallArgsJson = argsJson ?? "[]",
MarshalledCallAsyncHandle = default
};
var result = InternalCalls.InvokeJS<object, object, object, string>(out var exception, ref callInfo, null, null, null);
return exception != null
? throw new JSException(exception)
: result;
}
/// <inheritdoc />
protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson)
protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson, JSCallResultType resultType, long targetInstanceId)
{
InternalCalls.InvokeJSMarshalled(out _, ref asyncHandle, identifier, argsJson);
var callInfo = new JSCallInfo
{
FunctionIdentifier = identifier,
TargetInstanceId = targetInstanceId,
ResultType = resultType,
MarshalledCallArgsJson = argsJson ?? "[]",
MarshalledCallAsyncHandle = asyncHandle
};
InternalCalls.InvokeJS<object, object, object, string>(out _, ref callInfo, null, null, null);
}
protected override void EndInvokeDotNet(DotNetInvocationInfo callInfo, in DotNetInvocationResult dispatchResult)
@ -39,57 +57,32 @@ namespace Microsoft.JSInterop.WebAssembly
// We pass 0 as the async handle because we don't want the JS-side code to
// send back any notification (we're just providing a result for an existing async call)
var args = JsonSerializer.Serialize(new[] { callInfo.CallId, dispatchResult.Success, resultOrError }, JsonSerializerOptions);
BeginInvokeJS(0, "DotNet.jsCallDispatcher.endInvokeDotNetFromJS", args);
BeginInvokeJS(0, "DotNet.jsCallDispatcher.endInvokeDotNetFromJS", args, JSCallResultType.Default, 0);
}
/// <summary>
/// Invokes the JavaScript function registered with the specified identifier.
/// </summary>
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
/// <param name="identifier">The identifier used when registering the target function.</param>
/// <returns>The result of the function invocation.</returns>
public TResult InvokeUnmarshalled<TResult>(string identifier)
=> InvokeUnmarshalled<object, object, object, TResult>(identifier, null, null, null);
/// <inheritdoc />
TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<TResult>(string identifier)
=> ((IJSUnmarshalledRuntime)this).InvokeUnmarshalled<object, object, object, TResult>(identifier, null, null, null);
/// <summary>
/// Invokes the JavaScript function registered with the specified identifier.
/// </summary>
/// <typeparam name="T0">The type of the first argument.</typeparam>
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
/// <param name="identifier">The identifier used when registering the target function.</param>
/// <param name="arg0">The first argument.</param>
/// <returns>The result of the function invocation.</returns>
public TResult InvokeUnmarshalled<T0, TResult>(string identifier, T0 arg0)
=> InvokeUnmarshalled<T0, object, object, TResult>(identifier, arg0, null, null);
/// <inheritdoc />
TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<T0, TResult>(string identifier, T0 arg0)
=> ((IJSUnmarshalledRuntime)this).InvokeUnmarshalled<T0, object, object, TResult>(identifier, arg0, null, null);
/// <summary>
/// Invokes the JavaScript function registered with the specified identifier.
/// </summary>
/// <typeparam name="T0">The type of the first argument.</typeparam>
/// <typeparam name="T1">The type of the second argument.</typeparam>
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
/// <param name="identifier">The identifier used when registering the target function.</param>
/// <param name="arg0">The first argument.</param>
/// <param name="arg1">The second argument.</param>
/// <returns>The result of the function invocation.</returns>
public TResult InvokeUnmarshalled<T0, T1, TResult>(string identifier, T0 arg0, T1 arg1)
=> InvokeUnmarshalled<T0, T1, object, TResult>(identifier, arg0, arg1, null);
/// <inheritdoc />
TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<T0, T1, TResult>(string identifier, T0 arg0, T1 arg1)
=> ((IJSUnmarshalledRuntime)this).InvokeUnmarshalled<T0, T1, object, TResult>(identifier, arg0, arg1, null);
/// <summary>
/// Invokes the JavaScript function registered with the specified identifier.
/// </summary>
/// <typeparam name="T0">The type of the first argument.</typeparam>
/// <typeparam name="T1">The type of the second argument.</typeparam>
/// <typeparam name="T2">The type of the third argument.</typeparam>
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
/// <param name="identifier">The identifier used when registering the target function.</param>
/// <param name="arg0">The first argument.</param>
/// <param name="arg1">The second argument.</param>
/// <param name="arg2">The third argument.</param>
/// <returns>The result of the function invocation.</returns>
public TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
/// <inheritdoc />
TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
{
var result = InternalCalls.InvokeJSUnmarshalled<T0, T1, T2, TResult>(out var exception, identifier, arg0, arg1, arg2);
var callInfo = new JSCallInfo
{
FunctionIdentifier = identifier,
ResultType = ResultTypeFromGeneric<TResult>()
};
var result = InternalCalls.InvokeJS<T0, T1, T2, TResult>(out var exception, ref callInfo, arg0, arg1, arg2);
return exception != null
? throw new JSException(exception)
: result;

View File

@ -36,6 +36,8 @@
<Compile Include="..\src\BootJsonData.cs" LinkBase="Wasm" />
<Compile Include="..\src\AssetsManifestFile.cs" LinkBase="Wasm" />
<Compile Include="$(SharedSourceRoot)CommandLineUtils\**\*.cs" />
<EmbeddedResource Include="..\src\targets\BlazorWasm.web.config" />
</ItemGroup>
<Target Name="GenerateTestData" BeforeTargets="GetAssemblyAttributes">

View File

@ -4,6 +4,7 @@
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Testing;
using Microsoft.NET.Sdk.BlazorWebAssembly;
using Xunit;
@ -88,6 +89,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
}
[Fact]
[QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/23756")]
public async Task Publish_LazyLoadExplicitAssembly_Debug_Works()
{
// Arrange

View File

@ -113,6 +113,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
}
[Fact]
[QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/23756")]
public async Task Publish_WithoutLinkerAndCompression_IsIncremental()
{
// Arrange

View File

@ -41,6 +41,8 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
// Verify web.config
Assert.FileExists(result, publishDirectory, "web.config");
var webConfigContent = new StreamReader(GetType().Assembly.GetManifestResourceStream("Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests.BlazorWasm.web.config")).ReadToEnd();
Assert.FileContentEquals(result, Path.Combine(publishDirectory, "web.config"), webConfigContent);
Assert.FileCountEquals(result, 1, publishDirectory, "*", SearchOption.TopDirectoryOnly);
VerifyBootManifestHashes(result, blazorPublishDirectory);
@ -141,11 +143,10 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
serviceWorkerContent: "// This is the production service worker",
assetsManifestPath: "custom-service-worker-assets.js");
VerifyTypeGranularTrimming(result, blazorPublishDirectory);
}
[Fact]
[QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/23756")]
public async Task Publish_InRelease_Works()
{
// Arrange
@ -434,7 +435,8 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
Assert.Contains("System.Text.Json.dll", assemblies);
// No pdbs
Assert.Null(bootJsonData.resources.pdb);
// Testing this requires an update to the SDK in this repo. Re-enabling tracked via https://github.com/dotnet/aspnetcore/issues/25135
// Assert.Null(bootJsonData.resources.pdb);
Assert.Null(bootJsonData.resources.satelliteResources);
Assert.Contains("appsettings.json", bootJsonData.config);
@ -906,16 +908,17 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
private void VerifyTypeGranularTrimming(MSBuildResult result, string blazorPublishDirectory)
{
var loggingAssemblyPath = Path.Combine(blazorPublishDirectory, "_framework", "Microsoft.Extensions.Logging.Abstractions.dll");
Assert.FileExists(result, loggingAssemblyPath);
var componentsShimAssemblyPath = Path.Combine(blazorPublishDirectory, "_framework", "Microsoft.AspNetCore.Razor.Test.ComponentShim.dll");
Assert.FileExists(result, componentsShimAssemblyPath);
// ILogger is referenced by the app, so we expect it to be preserved
Assert.AssemblyContainsType(result, loggingAssemblyPath, "Microsoft.Extensions.Logging.ILogger");
// LogLevel is referenced by ILogger and therefore must be preserved.
Assert.AssemblyContainsType(result, loggingAssemblyPath, "Microsoft.Extensions.Logging.LogLevel");
// RouteView is referenced by the app, so we expect it to be preserved
Assert.AssemblyContainsType(result, componentsShimAssemblyPath, "Microsoft.AspNetCore.Components.RouteView");
// NullLogger is not referenced by the app, and should be trimmed.
Assert.AssemblyDoesNotContainType(result, loggingAssemblyPath, "Microsoft.Extensions.Logging.Abstractions.NullLogger");
// RouteData is referenced by RouteView so we expect it to be preserved.
Assert.AssemblyContainsType(result, componentsShimAssemblyPath, "Microsoft.AspNetCore.Components.RouteData");
// CascadingParameterAttribute is not referenced by the app, and should be trimmed.
Assert.AssemblyDoesNotContainType(result, componentsShimAssemblyPath, "Microsoft.AspNetCore.Components.CascadingParameterAttribute");
}
private static BootJsonData ReadBootJsonData(MSBuildResult result, string path)

View File

@ -54,7 +54,18 @@ namespace Microsoft.NET.Sdk.BlazorWebAssembly
}
}
protected override string GenerateCommandLineCommands() => ToolAssembly;
private static string Quote(string path)
{
if (string.IsNullOrEmpty(path) || (path[0] == '\"' && path[path.Length - 1] == '\"'))
{
// it's already quoted
return path;
}
return $"\"{path}\"";
}
protected override string GenerateCommandLineCommands() => Quote(ToolAssembly);
protected override string GenerateResponseFileCommands()
{

View File

@ -22,6 +22,9 @@ Copyright (c) .NET Foundation. All rights reserved.
<IsPackable>false</IsPackable>
<WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>
<!-- Turn off symbol publishing by default -->
<CopyOutputSymbolsToPublishDirectory>false</CopyOutputSymbolsToPublishDirectory>
</PropertyGroup>
<Import Sdk="Microsoft.NET.Sdk.Razor" Project="Sdk.props" />

View File

@ -53,6 +53,14 @@ Copyright (c) .NET Foundation. All rights reserved.
<!-- Trimmer defaults -->
<PublishTrimmed Condition="'$(PublishTrimmed)' == ''">true</PublishTrimmed>
<TrimMode Condition="'$(TrimMode)' == ''">link</TrimMode>
<TrimmerRemoveSymbols Condition="'$(TrimmerRemoveSymbols)' == ''">false</TrimmerRemoveSymbols>
<!-- Runtime feature defaults to trim unnecessary code -->
<EventSourceSupport Condition="'$(EventSourceSupport)' == ''">false</EventSourceSupport>
<UseSystemResourceKeys Condition="'$(UseSystemResourceKeys)' == ''">true</UseSystemResourceKeys>
<EnableUnsafeUTF7Encoding Condition="'$(EnableUnsafeUTF7Encoding)' == ''">false</EnableUnsafeUTF7Encoding>
<HttpActivityPropagationSupport Condition="'$(HttpActivityPropagationSupport)' == ''">false</HttpActivityPropagationSupport>
<DebuggerSupport Condition="'$(DebuggerSupport)' == '' and '$(Configuration)' != 'Debug'">false</DebuggerSupport>
<StaticWebAssetBasePath Condition="'$(StaticWebAssetBasePath)' == ''">/</StaticWebAssetBasePath>
<BlazorCacheBootResources Condition="'$(BlazorCacheBootResources)' == ''">true</BlazorCacheBootResources>
@ -69,6 +77,12 @@ Copyright (c) .NET Foundation. All rights reserved.
</PropertyGroup>
<ItemGroup>
<!-- Configuration for the platform compatibility analyzer. See https://github.com/dotnet/designs/blob/master/accepted/2020/platform-exclusion/platform-exclusion.md#build-configuration-for-platforms -->
<SupportedPlatform Remove="@(SupportedPlatform)" />
<SupportedPlatform Include="browser" />
</ItemGroup>
<Import Project="Microsoft.NET.Sdk.BlazorWebAssembly.ServiceWorkerAssetsManifest.targets" Condition="'$(ServiceWorkerAssetsManifest)' != ''" />
<Target Name="_ScrambleDotnetJsFileName" AfterTargets="ResolveRuntimePackAssets">
@ -395,7 +409,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<ItemGroup>
<_BlazorTypeGranularAssembly
Include="@(ManagedAssemblyToLink)"
Condition="'%(Extension)' == '.dll' AND ($([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.')) or $([System.String]::Copy('%(Filename)').StartsWith('Microsoft.Extensions.')))">
Condition="'%(Extension)' == '.dll' AND $([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.'))">
<Required>false</Required>
<Preserve>all</Preserve>
</_BlazorTypeGranularAssembly>
@ -451,7 +465,7 @@ Copyright (c) .NET Foundation. All rights reserved.
Condition="'%(ResolvedFileToPublish.RelativePath)' != 'web.config' AND !$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))" />
<!-- Remove pdbs from the publish output -->
<ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'$(BlazorWebAssemblyEnableDebugging)' != 'true' AND '%(Extension)' == '.pdb'" />
<ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'$(CopyOutputSymbolsToPublishDirectory)' != 'true' AND '%(Extension)' == '.pdb'" />
</ItemGroup>
<ItemGroup Condition="'@(ResolvedFileToPublish->AnyHaveMetadataValue('RelativePath', 'web.config'))' != 'true'">

View File

@ -8,7 +8,6 @@ namespace standalone
{
GC.KeepAlive(typeof(System.Text.Json.JsonSerializer));
GC.KeepAlive(typeof(RazorClassLibrary.Class1));
GC.KeepAlive(typeof(Microsoft.Extensions.Logging.ILogger));
#if REFERENCE_classlibrarywithsatelliteassemblies
GC.KeepAlive(typeof(classlibrarywithsatelliteassemblies.Class1));
#endif

View File

@ -0,0 +1,22 @@
// 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.Hosting
{
internal class RegisteredComponentsInterop
{
private static readonly string Prefix = "Blazor._internal.registeredComponents.";
public static readonly string GetRegisteredComponentsCount = Prefix + "getRegisteredComponentsCount";
public static readonly string GetId = Prefix + "getId";
public static readonly string GetAssembly = Prefix + "getAssembly";
public static readonly string GetTypeName = Prefix + "getTypeName";
public static readonly string GetParameterDefinitions = Prefix + "getParameterDefinitions";
public static readonly string GetParameterValues = Prefix + "getParameterValues";
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections;
using Microsoft.AspNetCore.Components;
namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
@ -16,7 +17,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
/// and <paramref name="selector"/>.
/// </summary>
/// <param name="componentType">The component type. Must implement <see cref="IComponent"/>.</param>
/// <param name="selector">The DOM element selector.</param>
/// <param name="selector">The DOM element selector or component registration id for the component.</param>
public RootComponentMapping(Type componentType, string selector)
{
if (componentType is null)
@ -38,6 +39,19 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
ComponentType = componentType;
Selector = selector;
Parameters = ParameterView.Empty;
}
/// <summary>
/// Creates a new instance of <see cref="RootComponentMapping"/> with the provided <paramref name="componentType"/>
/// and <paramref name="selector"/>.
/// </summary>
/// <param name="componentType">The component type. Must implement <see cref="IComponent"/>.</param>
/// <param name="selector">The DOM element selector or registration id for the component.</param>
/// <param name="parameters">The parameters to pass to the component.</param>
public RootComponentMapping(Type componentType, string selector, ParameterView parameters) : this(componentType, selector)
{
Parameters = parameters;
}
/// <summary>
@ -49,5 +63,10 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
/// Gets the DOM element selector.
/// </summary>
public string Selector { get; }
/// <summary>
/// Gets the parameters to pass to the root component.
/// </summary>
public ParameterView Parameters { get; }
}
}

View File

@ -34,6 +34,17 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
/// <param name="componentType">The component type. Must implement <see cref="IComponent"/>.</param>
/// <param name="selector">The DOM element selector.</param>
public void Add(Type componentType, string selector)
{
Add(componentType, selector, ParameterView.Empty);
}
/// <summary>
/// Adds a component mapping to the collection.
/// </summary>
/// <param name="componentType">The component type. Must implement <see cref="IComponent"/>.</param>
/// <param name="selector">The DOM element selector.</param>
/// <param name="parameters">The parameters to the root component.</param>
public void Add(Type componentType, string selector, ParameterView parameters)
{
if (componentType is null)
{
@ -45,7 +56,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
throw new ArgumentNullException(nameof(selector));
}
Add(new RootComponentMapping(componentType, selector));
Add(new RootComponentMapping(componentType, selector, parameters));
}
/// <summary>

View File

@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
for (var i = 0; i < rootComponents.Length; i++)
{
var rootComponent = rootComponents[i];
await _renderer.AddComponentAsync(rootComponent.ComponentType, rootComponent.Selector);
await _renderer.AddComponentAsync(rootComponent.ComponentType, rootComponent.Selector, rootComponent.Parameters);
}
await tcs.Task;

View File

@ -21,6 +21,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
public sealed class WebAssemblyHostBuilder
{
private Func<IServiceProvider> _createServiceProvider;
private RootComponentTypeCache _rootComponentCache;
/// <summary>
/// Creates an instance of <see cref="WebAssemblyHostBuilder"/> using the most common
@ -57,6 +58,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
// Retrieve required attributes from JSRuntimeInvoker
InitializeNavigationManager(jsRuntimeInvoker);
InitializeRegisteredRootComponents(jsRuntimeInvoker);
InitializeDefaultServices();
var hostEnvironment = InitializeEnvironment(jsRuntimeInvoker);
@ -68,6 +70,38 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
};
}
private void InitializeRegisteredRootComponents(WebAssemblyJSRuntimeInvoker jsRuntimeInvoker)
{
var componentsCount = jsRuntimeInvoker.InvokeUnmarshalled<object, object, object, int>(RegisteredComponentsInterop.GetRegisteredComponentsCount, null, null, null);
if (componentsCount == 0)
{
return;
}
var registeredComponents = new WebAssemblyComponentMarker[componentsCount];
for (var i = 0; i < componentsCount; i++)
{
var id = jsRuntimeInvoker.InvokeUnmarshalled<int, object, object, int>(RegisteredComponentsInterop.GetId, i, null, null);
var assembly = jsRuntimeInvoker.InvokeUnmarshalled<int, object, object, string>(RegisteredComponentsInterop.GetAssembly, id, null, null);
var typeName = jsRuntimeInvoker.InvokeUnmarshalled<int, object, object, string>(RegisteredComponentsInterop.GetTypeName, id, null, null);
var serializedParameterDefinitions = jsRuntimeInvoker.InvokeUnmarshalled<int, object, object, string>(RegisteredComponentsInterop.GetParameterDefinitions, id, null, null);
var serializedParameterValues = jsRuntimeInvoker.InvokeUnmarshalled<int, object, object, string>(RegisteredComponentsInterop.GetParameterValues, id, null, null);
registeredComponents[i] = new WebAssemblyComponentMarker(WebAssemblyComponentMarker.ClientMarkerType, assembly, typeName, serializedParameterDefinitions, serializedParameterValues, id.ToString());
}
var componentDeserializer = WebAssemblyComponentParameterDeserializer.Instance;
foreach (var registeredComponent in registeredComponents)
{
_rootComponentCache = new RootComponentTypeCache();
var componentType = _rootComponentCache.GetRootComponent(registeredComponent.Assembly, registeredComponent.TypeName);
var definitions = componentDeserializer.GetParameterDefinitions(registeredComponent.ParameterDefinitions);
var values = componentDeserializer.GetParameterValues(registeredComponent.ParameterValues);
var parameters = componentDeserializer.DeserializeParameters(definitions, values);
RootComponents.Add(componentType, registeredComponent.PrerenderId, parameters);
}
}
private void InitializeNavigationManager(WebAssemblyJSRuntimeInvoker jsRuntimeInvoker)
{
var baseUri = jsRuntimeInvoker.InvokeUnmarshalled<object, object, object, string>(BrowserNavigationManagerInterop.GetBaseUri, null, null, null);
@ -190,7 +224,8 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
Services.AddSingleton<NavigationManager>(WebAssemblyNavigationManager.Instance);
Services.AddSingleton<INavigationInterception>(WebAssemblyNavigationInterception.Instance);
Services.AddSingleton(new LazyAssemblyLoader(DefaultWebAssemblyJSRuntime.Instance));
Services.AddLogging(builder => {
Services.AddLogging(builder =>
{
builder.AddProvider(new WebAssemblyConsoleLoggerProvider(DefaultWebAssemblyJSRuntime.Instance));
});
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
@ -15,13 +15,7 @@
<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'" />
<ProjectReference Include="..\..\..\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj" ReferenceOutputAssemblies="false" SkipGetTargetFrameworkProperties="true" UndefineProperties="TargetFramework" Private="false" Condition="'$(BuildNodeJS)' != 'false' and '$(BuildingInsideVisualStudio)' != 'true'" />
<SuppressBaselineReference Include="Microsoft.AspNetCore.Components.WebAssembly.HttpHandler" />
</ItemGroup>
@ -31,6 +25,11 @@
<Compile Include="$(ComponentsSharedSourceRoot)src\JsonSerializerOptionsProvider.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\WebEventData.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\ElementReferenceJsonConverter.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\ComponentParametersTypeCache.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\RootComponentTypeCache.cs" />
<Compile Include="$(SharedSourceRoot)Components\WebAssemblyComponentSerializationSettings.cs" Link="Prerendering/WebAssemblyComponentSerializationSettings.cs" />
<Compile Include="$(SharedSourceRoot)Components\WebAssemblyComponentMarker.cs" Link="Prerendering/WebAssemblyComponentMarker.cs" />
<Compile Include="$(SharedSourceRoot)Components\ComponentParameter.cs" Link="Prerendering/ComponentParameter.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,88 @@
// 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.Text;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Components
{
internal class WebAssemblyComponentParameterDeserializer
{
private readonly ComponentParametersTypeCache _parametersCache;
public WebAssemblyComponentParameterDeserializer(
ComponentParametersTypeCache parametersCache)
{
_parametersCache = parametersCache;
}
public static WebAssemblyComponentParameterDeserializer Instance { get; } = new WebAssemblyComponentParameterDeserializer(new ComponentParametersTypeCache());
public ParameterView DeserializeParameters(IList<ComponentParameter> parametersDefinitions, IList<object> parameterValues)
{
var parametersDictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
if (parameterValues.Count != parametersDefinitions.Count)
{
// Mismatched number of definition/parameter values.
throw new InvalidOperationException($"The number of parameter definitions '{parametersDefinitions.Count}' does not match the number parameter values '{parameterValues.Count}'.");
}
for (var i = 0; i < parametersDefinitions.Count; i++)
{
var definition = parametersDefinitions[i];
if (definition.Name == null)
{
throw new InvalidOperationException("The name is missing in a parameter definition.");
}
if (definition.TypeName == null && definition.Assembly == null)
{
parametersDictionary[definition.Name] = null;
}
else if (definition.TypeName == null || definition.Assembly == null)
{
throw new InvalidOperationException($"The parameter definition for '{definition.Name}' is incomplete: Type='{definition.TypeName}' Assembly='{definition.Assembly}'.");
}
else
{
var parameterType = _parametersCache.GetParameterType(definition.Assembly, definition.TypeName);
if (parameterType == null)
{
throw new InvalidOperationException($"The parameter '{definition.Name} with type '{definition.TypeName}' in assembly '{definition.Assembly}' could not be found.");
}
try
{
var value = (JsonElement)parameterValues[i];
var parameterValue = JsonSerializer.Deserialize(
value.GetRawText(),
parameterType,
WebAssemblyComponentSerializationSettings.JsonSerializationOptions);
parametersDictionary[definition.Name] = parameterValue;
}
catch (Exception e)
{
throw new InvalidOperationException("Could not parse the parameter value for parameter '{definition.Name}' of type '{definition.TypeName}' and assembly '{definition.Assembly}'.", e);
}
}
}
return ParameterView.FromDictionary(parametersDictionary);
}
public ComponentParameter[] GetParameterDefinitions(string parametersDefinitions)
{
return JsonSerializer.Deserialize<ComponentParameter[]>(parametersDefinitions, WebAssemblyComponentSerializationSettings.JsonSerializationOptions);
}
public IList<object> GetParameterValues(string parameterValues)
{
return JsonSerializer.Deserialize<IList<object>>(parameterValues, WebAssemblyComponentSerializationSettings.JsonSerializationOptions);
}
}
}

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.RenderTree;
using Microsoft.AspNetCore.Components.WebAssembly.Services;
using Microsoft.Extensions.Logging;
using Microsoft.JSInterop;
using Microsoft.JSInterop.WebAssembly;
namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering
@ -46,13 +47,14 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering
/// </summary>
/// <typeparam name="TComponent">The type of the component.</typeparam>
/// <param name="domElementSelector">A CSS selector that uniquely identifies a DOM element.</param>
/// <param name="parameters">The parameters for the component.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous rendering of the added component.</returns>
/// <remarks>
/// Callers of this method may choose to ignore the returned <see cref="Task"/> if they do not
/// want to await the rendering of the added component.
/// </remarks>
public Task AddComponentAsync<TComponent>(string domElementSelector) where TComponent : IComponent
=> AddComponentAsync(typeof(TComponent), domElementSelector);
public Task AddComponentAsync<TComponent>(string domElementSelector, ParameterView parameters) where TComponent : IComponent
=> AddComponentAsync(typeof(TComponent), domElementSelector, parameters);
/// <summary>
/// Associates the <see cref="IComponent"/> with the <see cref="WebAssemblyRenderer"/>,
@ -60,12 +62,13 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering
/// </summary>
/// <param name="componentType">The type of the component.</param>
/// <param name="domElementSelector">A CSS selector that uniquely identifies a DOM element.</param>
/// <param name="parameters">The list of root component parameters.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous rendering of the added component.</returns>
/// <remarks>
/// Callers of this method may choose to ignore the returned <see cref="Task"/> if they do not
/// want to await the rendering of the added component.
/// </remarks>
public Task AddComponentAsync(Type componentType, string domElementSelector)
public Task AddComponentAsync(Type componentType, string domElementSelector, ParameterView parameters)
{
var component = InstantiateComponent(componentType);
var componentId = AssignRootComponentId(component);
@ -82,7 +85,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering
componentId,
_webAssemblyRendererId);
return RenderRootComponentAsync(componentId);
return RenderRootComponentAsync(componentId, parameters);
}
/// <inheritdoc />
@ -95,7 +98,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering
/// <inheritdoc />
protected override Task UpdateDisplayAsync(in RenderBatch batch)
{
DefaultWebAssemblyJSRuntime.Instance.InvokeUnmarshalled<int, RenderBatch, object>(
((IJSUnmarshalledRuntime)DefaultWebAssemblyJSRuntime.Instance).InvokeUnmarshalled<int, RenderBatch, object>(
"Blazor._internal.renderBatch",
_webAssemblyRendererId,
batch);

View File

@ -80,7 +80,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Services
var newAssembliesToLoad = assembliesToLoad.Where(assembly => !_loadedAssemblyCache.Contains(assembly));
var loadedAssemblies = new List<Assembly>();
var count = (int)await ((WebAssemblyJSRuntime)_jsRuntime).InvokeUnmarshalled<string[], object, object, Task<object>>(
var count = (int)await ((IJSUnmarshalledRuntime)_jsRuntime).InvokeUnmarshalled<string[], object, object, Task<object>>(
GetDynamicAssemblies,
newAssembliesToLoad.ToArray(),
null,
@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Services
return loadedAssemblies;
}
var assemblies = ((WebAssemblyJSRuntime)_jsRuntime).InvokeUnmarshalled<object, object, object, object[]>(
var assemblies = ((IJSUnmarshalledRuntime)_jsRuntime).InvokeUnmarshalled<object, object, object, object[]>(
ReadDynamicAssemblies,
null,
null,

View File

@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Services
_jsRuntime.InvokeVoid("console.error", formattedMessage);
break;
case LogLevel.Critical:
_jsRuntime.InvokeUnmarshalled<string, object>("Blazor._internal.dotNetCriticalError", formattedMessage);
((IJSUnmarshalledRuntime)_jsRuntime).InvokeUnmarshalled<string, object>("Blazor._internal.dotNetCriticalError", formattedMessage);
break;
default: // LogLevel.None or invalid enum values
Console.WriteLine(formattedMessage);

View File

@ -1,13 +1,13 @@
// 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.JSInterop.WebAssembly;
using Microsoft.JSInterop;
namespace Microsoft.AspNetCore.Components.WebAssembly.Services
{
/// <summary>
/// This class exists to enable unit testing for code that needs to call
/// <see cref="WebAssemblyJSRuntime.InvokeUnmarshalled{T0, T1, T2, TResult}(string, T0, T1, T2)"/>.
/// <see cref="IJSUnmarshalledRuntime.InvokeUnmarshalled{T0, T1, T2, TResult}(string, T0, T1, T2)"/>.
///
/// We should only use this in non-perf-critical code paths (for example, during hosting startup,
/// where we only call this a fixed number of times, and not during rendering where it might be
@ -22,6 +22,6 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Services
public static WebAssemblyJSRuntimeInvoker Instance = new WebAssemblyJSRuntimeInvoker();
public virtual TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
=> DefaultWebAssemblyJSRuntime.Instance.InvokeUnmarshalled<T0, T1, T2, TResult>(identifier, arg0, arg1, arg2);
=> ((IJSUnmarshalledRuntime)DefaultWebAssemblyJSRuntime.Instance).InvokeUnmarshalled<T0, T1, T2, TResult>(identifier, arg0, arg1, arg2);
}
}

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