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 # Test this script using changes in a fork
repository: 'dotnet/runtime' repository: 'dotnet/runtime'
path: runtime path: runtime
ref: release/5.0-rc1 ref: release/5.0
- name: Copy - name: Copy
shell: cmd shell: cmd
working-directory: .\runtime\src\libraries\Common\src\System\Net\Http\aspnetcore\ 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 EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "http2cat", "src\Servers\Kestrel\samples\http2cat\http2cat.csproj", "{8BDEC645-73BD-453B-8A5C-D616BC4EA08D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "http2cat", "src\Servers\Kestrel\samples\http2cat\http2cat.csproj", "{8BDEC645-73BD-453B-8A5C-D616BC4EA08D}"
EndProject 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}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Transport.Quic", "Transport.Quic", "{EE9D0952-6060-4723-B329-94A2950A6762}"
EndProject 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}" 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 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}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Http3SampleApp", "src\Servers\Kestrel\samples\Http3SampleApp\Http3SampleApp.csproj", "{2EC4E939-513F-44CD-A956-498966EAC929}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpStress", "src\Servers\Kestrel\stress\HttpStress.csproj", "{987E1C29-F124-40C8-8E6F-1B2B6A4CB62A}" 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 EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sdk", "Sdk", "{FED4267E-E5E4-49C5-98DB-8B3F203596EE}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sdk", "Sdk", "{FED4267E-E5E4-49C5-98DB-8B3F203596EE}"
EndProject 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 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 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 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 EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{6126DCE4-9692-4EE2-B240-C65743572995}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{6126DCE4-9692-4EE2-B240-C65743572995}"
EndProject EndProject
@ -1455,7 +1451,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropClient", "src\Grpc\t
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropWebsite", "src\Grpc\test\testassets\InteropWebsite\InteropWebsite.csproj", "{19189670-E206-471D-94F8-7D3D545E5020}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropWebsite", "src\Grpc\test\testassets\InteropWebsite\InteropWebsite.csproj", "{19189670-E206-471D-94F8-7D3D545E5020}"
EndProject 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 EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "src\Servers\IIS\IIS\test\testassets\InProcessWebSite\InProcessWebSite.csproj", "{8DA61885-B95E-4BA1-A752-C79B6597FC44}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "src\Servers\IIS\IIS\test\testassets\InProcessWebSite\InProcessWebSite.csproj", "{8DA61885-B95E-4BA1-A752-C79B6597FC44}"
EndProject EndProject
@ -1483,6 +1479,36 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Watch.
EndProject 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}" 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 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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|x64.Build.0 = Release|Any CPU
{8BDEC645-73BD-453B-8A5C-D616BC4EA08D}.Release|x86.ActiveCfg = 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 {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.ActiveCfg = Debug|Any CPU
{132D43A2-067A-4E24-A520-45B9F14DCB8E}.Debug|Any CPU.Build.0 = 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 {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|x64.Build.0 = Release|Any CPU
{132D43A2-067A-4E24-A520-45B9F14DCB8E}.Release|x86.ActiveCfg = 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 {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.ActiveCfg = Debug|Any CPU
{2EC4E939-513F-44CD-A956-498966EAC929}.Debug|Any CPU.Build.0 = 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 {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|x64.Build.0 = Release|Any CPU
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Release|x86.ActiveCfg = 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 {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.ActiveCfg = Debug|Any CPU
{46FB7E93-1294-4068-B80A-D4864F78277A}.Debug|Any CPU.Build.0 = 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 {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|x64.Build.0 = Release|Any CPU
{7E268085-1046-4362-80CB-2977FF826DCA}.Release|x86.ActiveCfg = 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 {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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -7771,10 +7893,8 @@ Global
{8550A02D-BA13-411A-AAD3-6124D33D669F} = {47EF1A9F-89DB-4EBA-9BC1-1D4E0E12DE44} {8550A02D-BA13-411A-AAD3-6124D33D669F} = {47EF1A9F-89DB-4EBA-9BC1-1D4E0E12DE44}
{EDE77D0C-321A-49FD-95D7-56ED41242A93} = {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} {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} {EE9D0952-6060-4723-B329-94A2950A6762} = {4FDDC525-4E60-4CAF-83A3-261C5B43721F}
{132D43A2-067A-4E24-A520-45B9F14DCB8E} = {EE9D0952-6060-4723-B329-94A2950A6762} {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} {2EC4E939-513F-44CD-A956-498966EAC929} = {7B976D8F-EA31-4C0B-97BD-DFD9B3CC86FB}
{987E1C29-F124-40C8-8E6F-1B2B6A4CB62A} = {4FDDC525-4E60-4CAF-83A3-261C5B43721F} {987E1C29-F124-40C8-8E6F-1B2B6A4CB62A} = {4FDDC525-4E60-4CAF-83A3-261C5B43721F}
{3CBC4802-E9B8-48B7-BC8C-B0AFB9EEC643} = {0ACCEDA7-339C-4B4D-8DD4-1AC271F31C04} {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} {83371889-9A3E-4D16-AE77-EB4F83BC6374} = {FED4267E-E5E4-49C5-98DB-8B3F203596EE}
{525EBCB4-A870-470B-BC90-845306C337D1} = {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} {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} {6126DCE4-9692-4EE2-B240-C65743572995} = {0508E463-0269-40C9-B5C2-3B600FB2A28B}
{46FB7E93-1294-4068-B80A-D4864F78277A} = {6126DCE4-9692-4EE2-B240-C65743572995} {46FB7E93-1294-4068-B80A-D4864F78277A} = {6126DCE4-9692-4EE2-B240-C65743572995}
{25FA84DB-EEA7-4068-8E2D-F3D48B281C16} = {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} {7F87406C-A3C8-4139-A68D-E4C344294A67} = {D62AF49B-F9FE-4794-AC39-A473FF13CA81}
{1533E271-F61B-441B-8B74-59FB61DF0552} = {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} {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 EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F} SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F}

View File

@ -268,3 +268,28 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 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.ComponentModel.Annotations" />
<LatestPackageReference Include="System.Diagnostics.DiagnosticSource" /> <LatestPackageReference Include="System.Diagnostics.DiagnosticSource" />
<LatestPackageReference Include="System.Diagnostics.EventLog" /> <LatestPackageReference Include="System.Diagnostics.EventLog" />
<LatestPackageReference Include="System.DirectoryServices.Protocols" />
<LatestPackageReference Include="System.Drawing.Common" /> <LatestPackageReference Include="System.Drawing.Common" />
<LatestPackageReference Include="System.IO.Pipelines" /> <LatestPackageReference Include="System.IO.Pipelines" />
<LatestPackageReference Include="System.Net.Http" /> <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.Bcl.AsyncInterfaces" />
<LatestPackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" /> <LatestPackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" />
<LatestPackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" /> <LatestPackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" />
<LatestPackageReference Include="Microsoft.EntityFrameworkCore.Design" />
<LatestPackageReference Include="Microsoft.EntityFrameworkCore.InMemory" /> <LatestPackageReference Include="Microsoft.EntityFrameworkCore.InMemory" />
<LatestPackageReference Include="Microsoft.EntityFrameworkCore.Relational" /> <LatestPackageReference Include="Microsoft.EntityFrameworkCore.Relational" />
<LatestPackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" /> <LatestPackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />

View File

@ -13,305 +13,313 @@
<Uri>https://github.com/dotnet/blazor</Uri> <Uri>https://github.com/dotnet/blazor</Uri>
<Sha>cc449601d638ffaab58ae9487f0fd010bb178a12</Sha> <Sha>cc449601d638ffaab58ae9487f0fd010bb178a12</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha> <Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha> <Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha> <Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha> <Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha> <Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha> <Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/efcore</Uri>
<Sha>5099d918192f5df031e1ff5e3beea9cb361c605a</Sha> <Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency> </Dependency>
<Dependency Name="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0-rc.1.20416.7"> <Dependency Name="Microsoft.EntityFrameworkCore.Design" Version="5.0.0-rc.1.20425.4">
<Uri>https://github.com/dotnet/runtime</Uri> <Uri>https://github.com/dotnet/efcore</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>9638c0cda4bfb2eb8b70a047baefc982ffa7dade</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <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> </Dependency>
<!-- System.Security.AccessControl should only be referenced in Dependencies.props and RTMVersions.csproj. --> <!-- 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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </Dependency>
<!-- <!--
Win-x64 is used here because we have picked an arbitrary runtime identifier to flow the version of the latest NETCore.App runtime. 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. 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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </Dependency>
</ProductDependencies> </ProductDependencies>
<ToolsetDependencies> <ToolsetDependencies>
<!-- Listed explicitly to workaround https://github.com/dotnet/cli/issues/10528 --> <!-- 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> <Uri>https://github.com/dotnet/runtime</Uri>
<Sha>0862d48a9c9fbda879206b194a16d8e607deac42</Sha> <Sha>f4e99f4afa445b519abcd7c5c87cbf54771614db</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/arcade</Uri>
<Sha>ecec08a0eebbd92bb9538e351d475582551d9092</Sha> <Sha>56a95cc477558c1ccdf16d7abe962849ea970ba4</Sha>
</Dependency> </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> <Uri>https://github.com/dotnet/arcade</Uri>
<Sha>ecec08a0eebbd92bb9538e351d475582551d9092</Sha> <Sha>56a95cc477558c1ccdf16d7abe962849ea970ba4</Sha>
</Dependency> </Dependency>
<Dependency Name="Microsoft.Net.Compilers.Toolset" Version="3.8.0-2.20407.3"> <Dependency Name="Microsoft.Net.Compilers.Toolset" Version="3.8.0-2.20407.3">
<Uri>https://github.com/dotnet/roslyn</Uri> <Uri>https://github.com/dotnet/roslyn</Uri>

View File

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

View File

@ -19,7 +19,9 @@ if(TARGET_ARCH_NAME STREQUAL "armel")
endif() endif()
elseif(TARGET_ARCH_NAME STREQUAL "arm") elseif(TARGET_ARCH_NAME STREQUAL "arm")
set(CMAKE_SYSTEM_PROCESSOR armv7l) 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") set(TOOLCHAIN "armv6-alpine-linux-musleabihf")
else() else()
set(TOOLCHAIN "arm-linux-gnueabihf") set(TOOLCHAIN "arm-linux-gnueabihf")

View File

@ -199,14 +199,15 @@ if [[ "$mono_dotnet" != "" ]]; then
fi fi
if [[ "$wasm_runtime_loc" != "" ]]; then 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 fi
if [[ "$monointerpreter" == "true" ]]; then if [[ "$monointerpreter" == "true" ]]; then
extra_benchmark_dotnet_arguments="$extra_benchmark_dotnet_arguments --category-exclusion-filter NoInterpreter" extra_benchmark_dotnet_arguments="$extra_benchmark_dotnet_arguments --category-exclusion-filter NoInterpreter"
fi 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" 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( param(
[Parameter(Mandatory=$true)][int] $BuildId, [Parameter(Mandatory=$true)][int] $BuildId,
[Parameter(Mandatory=$true)][int] $PublishingInfraVersion,
[Parameter(Mandatory=$true)][string] $AzdoToken, [Parameter(Mandatory=$true)][string] $AzdoToken,
[Parameter(Mandatory=$true)][string] $MaestroToken, [Parameter(Mandatory=$true)][string] $MaestroToken,
[Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro-prod.westus2.cloudapp.azure.com', [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro-prod.westus2.cloudapp.azure.com',
[Parameter(Mandatory=$true)][string] $WaitPublishingFinish, [Parameter(Mandatory=$true)][string] $WaitPublishingFinish,
[Parameter(Mandatory=$true)][string] $EnableSourceLinkValidation, [Parameter(Mandatory=$false)][string] $EnableSourceLinkValidation,
[Parameter(Mandatory=$true)][string] $EnableSigningValidation, [Parameter(Mandatory=$false)][string] $EnableSigningValidation,
[Parameter(Mandatory=$true)][string] $EnableNugetValidation, [Parameter(Mandatory=$false)][string] $EnableNugetValidation,
[Parameter(Mandatory=$true)][string] $PublishInstallersAndChecksums, [Parameter(Mandatory=$true)][string] $PublishInstallersAndChecksums,
[Parameter(Mandatory=$false)][string] $ArtifactsPublishingAdditionalParameters, [Parameter(Mandatory=$false)][string] $ArtifactsPublishingAdditionalParameters,
[Parameter(Mandatory=$false)][string] $SigningValidationAdditionalParameters [Parameter(Mandatory=$false)][string] $SigningValidationAdditionalParameters
@ -14,7 +15,8 @@ param(
try { try {
. $PSScriptRoot\post-build-utils.ps1 . $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() $optionalParams = [System.Collections.ArrayList]::new()
@ -49,12 +51,13 @@ try {
} }
& darc add-build-to-channel ` & darc add-build-to-channel `
--id $buildId ` --id $buildId `
--default-channels ` --publishing-infra-version $PublishingInfraVersion `
--source-branch master ` --default-channels `
--azdev-pat $AzdoToken ` --source-branch master `
--bar-uri $MaestroApiEndPoint ` --azdev-pat $AzdoToken `
--password $MaestroToken ` --bar-uri $MaestroApiEndPoint `
--password $MaestroToken `
@optionalParams @optionalParams
if ($LastExitCode -ne 0) { if ($LastExitCode -ne 0) {

View File

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

View File

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

View File

@ -1,13 +1,20 @@
parameters: 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 # 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 # otherwise Darc add-build-to-channel will be used to trigger the promotion pipeline
inline: true inline: true
# Only used if inline==false. When set to true will stall the current build until # 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. # execution concurrently with the promotion build.
waitPublishingFinish: true waitPublishingFinish: true
BARBuildId: ''
PromoteToChannelIds: ''
enableSourceLinkValidation: false enableSourceLinkValidation: false
enableSigningValidation: true enableSigningValidation: true
enableSymbolValidation: false enableSymbolValidation: false
@ -39,6 +46,7 @@ parameters:
NetEngLatestChannelId: 2 NetEngLatestChannelId: 2
NetEngValidationChannelId: 9 NetEngValidationChannelId: 9
NetDev5ChannelId: 131 NetDev5ChannelId: 131
NetDev6ChannelId: 1296
GeneralTestingChannelId: 529 GeneralTestingChannelId: 529
NETCoreToolingDevChannelId: 548 NETCoreToolingDevChannelId: 548
NETCoreToolingReleaseChannelId: 549 NETCoreToolingReleaseChannelId: 549
@ -46,7 +54,6 @@ parameters:
NETCoreExperimentalChannelId: 562 NETCoreExperimentalChannelId: 562
NetEngServicesIntChannelId: 678 NetEngServicesIntChannelId: 678
NetEngServicesProdChannelId: 679 NetEngServicesProdChannelId: 679
Net5Preview7ChannelId: 1065
Net5Preview8ChannelId: 1155 Net5Preview8ChannelId: 1155
Net5RC1ChannelId: 1157 Net5RC1ChannelId: 1157
NetCoreSDK313xxChannelId: 759 NetCoreSDK313xxChannelId: 759
@ -59,14 +66,183 @@ parameters:
VSMasterChannelId: 1012 VSMasterChannelId: 1012
stages: 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 - stage: publish_using_darc
dependsOn: ${{ parameters.validateDependsOn }} dependsOn: Validate
displayName: Publish using Darc displayName: Publish using Darc
variables: variables:
- template: common-variables.yml - template: common-variables.yml
jobs: jobs:
- template: setup-maestro-vars.yml - template: setup-maestro-vars.yml
parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
- job: - job:
displayName: Publish Using Darc displayName: Publish Using Darc
@ -82,182 +258,17 @@ stages:
inputs: inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
arguments: -BuildId $(BARBuildId) arguments: -BuildId $(BARBuildId)
-PublishingInfraVersion ${{ parameters.PublishingInfraVersion }}
-AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
-MaestroToken '$(MaestroApiAccessToken)' -MaestroToken '$(MaestroApiAccessToken)'
-WaitPublishingFinish ${{ parameters.waitPublishingFinish }} -WaitPublishingFinish ${{ parameters.waitPublishingFinish }}
-EnableSourceLinkValidation ${{ parameters.enableSourceLinkValidation }}
-EnableSigningValidation ${{ parameters.enableSourceLinkValidation }}
-EnableNugetValidation ${{ parameters.enableSourceLinkValidation }}
-PublishInstallersAndChecksums ${{ parameters.publishInstallersAndChecksums }} -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 - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -272,20 +283,24 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
stageName: 'Net5_Preview7_Publish' stageName: 'NetCore_Dev6_Publish'
channelName: '.NET 5 Preview 7' channelName: '.NET 6 Dev'
akaMSChannelName: 'net5/preview7' akaMSChannelName: 'net6/dev'
channelId: ${{ parameters.Net5Preview7ChannelId }} channelId: ${{ parameters.NetDev6ChannelId }}
transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-transport/nuget/v3/index.json' transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6-transport/nuget/v3/index.json'
shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/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/dotnet5-symbols/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 - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -298,8 +313,10 @@ stages:
shippingFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal/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' 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: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -308,12 +325,14 @@ stages:
channelName: '.NET 5 RC 1' channelName: '.NET 5 RC 1'
akaMSChannelName: 'net5/rc1' akaMSChannelName: 'net5/rc1'
channelId: ${{ parameters.Net5RC1ChannelId }} channelId: ${{ parameters.Net5RC1ChannelId }}
transportFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal-transport/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/internal/_packaging/dotnet5-internal/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/internal/_packaging/dotnet5-internal-symbols/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 - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -328,6 +347,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -342,6 +363,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -356,6 +379,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -369,6 +394,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -382,6 +409,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-internal-channel.yml - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -395,6 +424,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -408,6 +439,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -421,6 +454,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -434,6 +469,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -447,6 +484,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-internal-channel.yml - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -460,6 +499,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -473,6 +514,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-internal-channel.yml - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -486,6 +529,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -499,6 +544,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -512,6 +559,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
@ -525,6 +574,8 @@ stages:
- template: \eng\common\templates\post-build\channels\generic-public-channel.yml - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
parameters: parameters:
BARBuildId: ${{ parameters.BARBuildId }}
PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
dependsOn: ${{ parameters.publishDependsOn }} dependsOn: ${{ parameters.publishDependsOn }}
publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}

View File

@ -1,25 +1,23 @@
parameters:
BARBuildId: ''
PromoteToChannelIds: ''
jobs: jobs:
- job: setupMaestroVars - job: setupMaestroVars
displayName: Setup Maestro Vars displayName: Setup Maestro Vars
variables: variables:
- template: common-variables.yml - 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: pool:
vmImage: 'windows-2019' vmImage: 'windows-2019'
steps: steps:
- checkout: none - checkout: none
- task: DownloadBuildArtifacts@0 - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}:
displayName: Download Release Configs - task: DownloadBuildArtifacts@0
condition: and(eq(variables.PromoteToMaestroChannels, 0), eq(variables.PromoteToMaestroChannel, 0)) displayName: Download Release Configs
inputs: inputs:
buildType: current buildType: current
artifactName: ReleaseConfigs artifactName: ReleaseConfigs
- task: PowerShell@2 - task: PowerShell@2
name: setReleaseVars name: setReleaseVars
@ -28,7 +26,7 @@ jobs:
targetType: inline targetType: inline
script: | script: |
try { 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 $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt
$BarId = $Content | Select -Index 0 $BarId = $Content | Select -Index 0
@ -51,7 +49,7 @@ jobs:
$BarId = $Env:BARBuildId $BarId = $Env:BARBuildId
$Channels = $Env:PromoteToMaestroChannels -split "," $Channels = $Env:PromoteToMaestroChannels -split ","
$Channels = $Channels -join "][" $Channels = $Channels -join "]["
$Channels = "[$Channels][$Env:PromoteToMaestroChannel]" $Channels = "[$Channels]"
$IsStableBuild = $buildInfo.stable $IsStableBuild = $buildInfo.stable
$AzureDevOpsProject = $buildInfo.azureDevOpsProject $AzureDevOpsProject = $buildInfo.azureDevOpsProject
@ -75,3 +73,5 @@ jobs:
} }
env: env:
MAESTRO_API_TOKEN: $(MaestroApiAccessToken) 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 & $PSScriptRoot\Download.ps1 "https://dot.net/v1/dotnet-install.ps1" $PSScriptRoot\dotnet-install.ps1
Write-Host "Download of dotnet-install.ps1 complete..." Write-Host "Download of dotnet-install.ps1 complete..."
Write-Host "Installing SDK...& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Version $sdkVersion -InstallDir $installDir" 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" 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" 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" Invoke-Expression "& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Runtime dotnet -Version $runtimeVersion -InstallDir $installDir -NoPath"
Write-Host "InstallDotNet.ps1 complete..." Write-Host "InstallDotNet.ps1 complete..."

View File

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

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -57,7 +58,24 @@ namespace Microsoft.AspNetCore.Antiforgery
{ {
// Check the content-type before accessing the form collection to make sure // Check the content-type before accessing the form collection to make sure
// we report errors gracefully. // 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]; requestToken = form[_options.FormFieldName];
} }

View File

@ -136,6 +136,9 @@
<data name="AntiforgeryToken_TokensSwapped" xml:space="preserve"> <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> <value>Validation of the provided antiforgery token failed. The cookie token and the request token were swapped.</value>
</data> </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"> <data name="AntiforgeryToken_UsernameMismatch" xml:space="preserve">
<value>The provided antiforgery token was meant for user "{0}", but the current user is "{1}".</value> <value>The provided antiforgery token was meant for user "{0}", but the current user is "{1}".</value>
</data> </data>

View File

@ -3,6 +3,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
@ -235,6 +237,56 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
Assert.Null(tokenSet.RequestToken); 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] [Theory]
[InlineData(false, CookieSecurePolicy.SameAsRequest, null)] [InlineData(false, CookieSecurePolicy.SameAsRequest, null)]
[InlineData(true, CookieSecurePolicy.SameAsRequest, true)] [InlineData(true, CookieSecurePolicy.SameAsRequest, true)]

View File

@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Components
( (
propertyName: property.Name, propertyName: property.Name,
propertyType: property.PropertyType, propertyType: property.PropertyType,
setter: MemberAssignment.CreatePropertySetter(type, property, cascading: false) setter: new PropertySetter(type, property)
)).ToArray(); )).ToArray();
return Initialize; 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 try
{ {
@ -246,13 +246,13 @@ namespace Microsoft.AspNetCore.Components.Reflection
private class WritersForType private class WritersForType
{ {
private const int MaxCachedWriterLookups = 100; private const int MaxCachedWriterLookups = 100;
private readonly Dictionary<string, IPropertySetter> _underlyingWriters; private readonly Dictionary<string, PropertySetter> _underlyingWriters;
private readonly ConcurrentDictionary<string, IPropertySetter?> _referenceEqualityWritersCache; private readonly ConcurrentDictionary<string, PropertySetter?> _referenceEqualityWritersCache;
public WritersForType(Type targetType) public WritersForType(Type targetType)
{ {
_underlyingWriters = new Dictionary<string, IPropertySetter>(StringComparer.OrdinalIgnoreCase); _underlyingWriters = new Dictionary<string, PropertySetter>(StringComparer.OrdinalIgnoreCase);
_referenceEqualityWritersCache = new ConcurrentDictionary<string, IPropertySetter?>(ReferenceEqualityComparer.Instance); _referenceEqualityWritersCache = new ConcurrentDictionary<string, PropertySetter?>(ReferenceEqualityComparer.Instance);
foreach (var propertyInfo in GetCandidateBindableProperties(targetType)) 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."); $"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)) if (_underlyingWriters.ContainsKey(propertyName))
{ {
@ -298,17 +301,17 @@ namespace Microsoft.AspNetCore.Components.Reflection
ThrowForInvalidCaptureUnmatchedValuesParameterType(targetType, propertyInfo); ThrowForInvalidCaptureUnmatchedValuesParameterType(targetType, propertyInfo);
} }
CaptureUnmatchedValuesWriter = MemberAssignment.CreatePropertySetter(targetType, propertyInfo, cascading: false); CaptureUnmatchedValuesWriter = new PropertySetter(targetType, propertyInfo);
CaptureUnmatchedValuesPropertyName = propertyInfo.Name; CaptureUnmatchedValuesPropertyName = propertyInfo.Name;
} }
} }
} }
public IPropertySetter? CaptureUnmatchedValuesWriter { get; } public PropertySetter? CaptureUnmatchedValuesWriter { get; }
public string? CaptureUnmatchedValuesPropertyName { 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 // 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. // 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. // 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. // 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 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); 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> /// <summary>
/// Gets or sets a handler that should be called before navigating to a new page. /// Gets or sets a handler that should be called before navigating to a new page.
/// </summary> /// </summary>
[Parameter] public Func<NavigationContext, Task>? OnNavigateAsync { get; set; } [Parameter] public EventCallback<NavigationContext> OnNavigateAsync { get; set; }
private RouteTable Routes { get; set; } private RouteTable Routes { get; set; }
@ -115,8 +115,7 @@ namespace Microsoft.AspNetCore.Components.Routing
if (!_onNavigateCalled) if (!_onNavigateCalled)
{ {
_onNavigateCalled = true; _onNavigateCalled = true;
await RunOnNavigateWithRefreshAsync(NavigationManager.ToBaseRelativePath(_locationAbsolute), isNavigationIntercepted: false); await RunOnNavigateAsync(NavigationManager.ToBaseRelativePath(_locationAbsolute), isNavigationIntercepted: false);
return;
} }
Refresh(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 // Cancel the CTS instead of disposing it, since disposing does not
// actually cancel and can cause unintended Object Disposed Exceptions. // actually cancel and can cause unintended Object Disposed Exceptions.
// This effectivelly cancels the previously running task and completes it. // 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 // 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 // for the previous task was set but not fully completed by the time we get to this
// invocation. // 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(); _onNavigateCts = new CancellationTokenSource();
var navigateContext = new NavigationContext(path, _onNavigateCts.Token); var navigateContext = new NavigationContext(path, _onNavigateCts.Token);
var cancellationTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
navigateContext.CancellationToken.Register(state =>
((TaskCompletionSource)state).SetResult(), cancellationTcs);
try try
{ {
if (Navigating != null) // 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);
_renderHandle.Render(Navigating); await task;
} tcs.SetResult();
await OnNavigateAsync(navigateContext); Refresh(isNavigationIntercepted);
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));
}
} }
catch (Exception e) catch (Exception e)
{ {
_renderHandle.Render(builder => ExceptionDispatchInfo.Throw(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) private void OnLocationChanged(object sender, LocationChangedEventArgs args)
@ -277,7 +251,7 @@ namespace Microsoft.AspNetCore.Components.Routing
_locationAbsolute = args.Location; _locationAbsolute = args.Location;
if (_renderHandle.IsInitialized && Routes != null) 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.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit; using Xunit;
using Microsoft.AspNetCore.Components;
namespace Microsoft.AspNetCore.Components.Test.Routing namespace Microsoft.AspNetCore.Components.Test.Routing
{ {
@ -42,49 +40,26 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
{ {
// Arrange // Arrange
var called = false; var called = false;
async Task OnNavigateAsync(NavigationContext args) Action<NavigationContext> OnNavigateAsync = async (NavigationContext args) =>
{ {
await Task.CompletedTask; await Task.CompletedTask;
called = true; called = true;
} };
_router.OnNavigateAsync = OnNavigateAsync; _router.OnNavigateAsync = new EventCallback<NavigationContext>(null, OnNavigateAsync);
// Act // 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
Assert.True(called); 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] [Fact]
public async Task CanceledFailedOnNavigateAsyncDoesNothing() public async Task CanceledFailedOnNavigateAsyncDoesNothing()
{ {
// Arrange // Arrange
var onNavigateInvoked = 0; var onNavigateInvoked = 0;
async Task OnNavigateAsync(NavigationContext args) Action<NavigationContext> OnNavigateAsync = async (NavigationContext args) =>
{ {
onNavigateInvoked += 1; onNavigateInvoked += 1;
if (args.Path.EndsWith("jan")) if (args.Path.EndsWith("jan"))
@ -92,22 +67,18 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
await Task.Delay(Timeout.Infinite, args.CancellationToken); await Task.Delay(Timeout.Infinite, args.CancellationToken);
throw new Exception("This is an uncaught exception."); throw new Exception("This is an uncaught exception.");
} }
} };
var refreshCalled = false; var refreshCalled = 0;
_renderer.OnUpdateDisplay = (renderBatch) => _renderer.OnUpdateDisplay = (renderBatch) =>
{ {
if (!refreshCalled) refreshCalled += 1;
{ return;
refreshCalled = true;
return;
}
Assert.True(false, "OnUpdateDisplay called more than once.");
}; };
_router.OnNavigateAsync = OnNavigateAsync; _router.OnNavigateAsync = new EventCallback<NavigationContext>(null, OnNavigateAsync);
// Act // Act
var janTask = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false)); var janTask = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/jan", false));
var febTask = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/feb", false)); var febTask = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/feb", false));
await janTask; await janTask;
await febTask; 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 that we render the second route component and don't throw an exception
Assert.Empty(_renderer.HandledExceptions); Assert.Empty(_renderer.HandledExceptions);
Assert.Equal(2, onNavigateInvoked); Assert.Equal(2, onNavigateInvoked);
} Assert.Equal(2, refreshCalled);
[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);
} }
[Fact] [Fact]
@ -144,7 +94,7 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
{ {
// Arrange // Arrange
var triggerCancel = new TaskCompletionSource(); var triggerCancel = new TaskCompletionSource();
async Task OnNavigateAsync(NavigationContext args) Action<NavigationContext> OnNavigateAsync = async (NavigationContext args) =>
{ {
if (args.Path.EndsWith("jan")) if (args.Path.EndsWith("jan"))
{ {
@ -153,7 +103,7 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
tcs.TrySetCanceled(); tcs.TrySetCanceled();
await tcs.Task; await tcs.Task;
} }
} };
var refreshCalled = false; var refreshCalled = false;
_renderer.OnUpdateDisplay = (renderBatch) => _renderer.OnUpdateDisplay = (renderBatch) =>
{ {
@ -164,11 +114,11 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
} }
Assert.True(false, "OnUpdateDisplay called more than once."); 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) // Act (start the operations then await them)
var jan = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false)); var jan = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/jan", false));
var feb = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/feb", false)); var feb = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/feb", false));
triggerCancel.TrySetResult(); triggerCancel.TrySetResult();
await jan; await jan;
@ -180,16 +130,16 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
{ {
// Arrange // Arrange
var cancelled = ""; var cancelled = "";
async Task OnNavigateAsync(NavigationContext args) Action<NavigationContext> OnNavigateAsync = async (NavigationContext args) =>
{ {
await Task.CompletedTask; await Task.CompletedTask;
args.CancellationToken.Register(() => cancelled = args.Path); args.CancellationToken.Register(() => cancelled = args.Path);
}; };
_router.OnNavigateAsync = OnNavigateAsync; _router.OnNavigateAsync = new EventCallback<NavigationContext>(null, OnNavigateAsync);
// Act // Act
_ = _router.RunOnNavigateWithRefreshAsync("jan", false); _ = _router.RunOnNavigateAsync("jan", false);
_ = _router.RunOnNavigateWithRefreshAsync("feb", false); _ = _router.RunOnNavigateAsync("feb", false);
// Assert // Assert
var expected = "jan"; var expected = "jan";
@ -200,7 +150,7 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
public async Task RefreshesOnceOnCancelledOnNavigateAsync() public async Task RefreshesOnceOnCancelledOnNavigateAsync()
{ {
// Arrange // Arrange
async Task OnNavigateAsync(NavigationContext args) Action<NavigationContext> OnNavigateAsync = async (NavigationContext args) =>
{ {
if (args.Path.EndsWith("jan")) if (args.Path.EndsWith("jan"))
{ {
@ -217,11 +167,11 @@ namespace Microsoft.AspNetCore.Components.Test.Routing
} }
Assert.True(false, "OnUpdateDisplay called more than once."); Assert.True(false, "OnUpdateDisplay called more than once.");
}; };
_router.OnNavigateAsync = OnNavigateAsync; _router.OnNavigateAsync = new EventCallback<NavigationContext>(null, OnNavigateAsync);
// Act // Act
var jan = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false)); var jan = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/jan", false));
var feb = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/feb", false)); var feb = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateAsync("http://example.com/feb", false));
await jan; await jan;
await feb; await feb;

View File

@ -22,6 +22,10 @@
"src\\Components\\WebAssembly\\DebugProxy\\src\\Microsoft.AspNetCore.Components.WebAssembly.DebugProxy.csproj", "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\\DevServer\\src\\Microsoft.AspNetCore.Components.WebAssembly.DevServer.csproj",
"src\\Components\\WebAssembly\\JSInterop\\src\\Microsoft.JSInterop.WebAssembly.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\\src\\Microsoft.AspNetCore.Components.WebAssembly.Server.csproj",
"src\\Components\\WebAssembly\\Server\\test\\Microsoft.AspNetCore.Components.WebAssembly.Server.Tests.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", "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.Client\\HostedInAspNet.Client.csproj",
"src\\Components\\WebAssembly\\testassets\\HostedInAspNet.Server\\HostedInAspNet.Server.csproj", "src\\Components\\WebAssembly\\testassets\\HostedInAspNet.Server\\HostedInAspNet.Server.csproj",
"src\\Components\\WebAssembly\\testassets\\StandaloneApp\\StandaloneApp.csproj", "src\\Components\\WebAssembly\\testassets\\StandaloneApp\\StandaloneApp.csproj",
"src\\Components\\WebAssembly\\Sdk\\src\\Microsoft.NET.Sdk.BlazorWebAssembly.csproj", "src\\Components\\WebAssembly\\testassets\\Wasm.Authentication.Client\\Wasm.Authentication.Client.csproj",
"src\\Components\\WebAssembly\\Sdk\\test\\Microsoft.NET.Sdk.BlazorWebAssembly.Tests.csproj", "src\\Components\\WebAssembly\\testassets\\Wasm.Authentication.Server\\Wasm.Authentication.Server.csproj",
"src\\Components\\WebAssembly\\Sdk\\tools\\Microsoft.NET.Sdk.BlazorWebAssembly.Tools.csproj", "src\\Components\\WebAssembly\\testassets\\Wasm.Authentication.Shared\\Wasm.Authentication.Shared.csproj",
"src\\Components\\WebAssembly\\Sdk\\integrationtests\\Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests.csproj",
"src\\Components\\Web\\src\\Microsoft.AspNetCore.Components.Web.csproj", "src\\Components\\Web\\src\\Microsoft.AspNetCore.Components.Web.csproj",
"src\\Components\\Web\\test\\Microsoft.AspNetCore.Components.Web.Tests.csproj", "src\\Components\\Web\\test\\Microsoft.AspNetCore.Components.Web.Tests.csproj",
"src\\Components\\benchmarkapps\\Wasm.Performance\\ConsoleHost\\Wasm.Performance.ConsoleHost.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 // really don't, you can pass an empty object then ignore it. Ensuring it's nonnull
// simplifies things for all consumers of EditContext. // simplifies things for all consumers of EditContext.
Model = model ?? throw new ArgumentNullException(nameof(model)); Model = model ?? throw new ArgumentNullException(nameof(model));
Properties = new EditContextProperties();
} }
/// <summary> /// <summary>
@ -62,6 +63,11 @@ namespace Microsoft.AspNetCore.Components.Forms
/// </summary> /// </summary>
public object Model { get; } public object Model { get; }
/// <summary>
/// Gets a collection of arbitrary properties associated with this instance.
/// </summary>
public EditContextProperties Properties { get; }
/// <summary> /// <summary>
/// Signals that the value for the specified field has changed. /// Signals that the value for the specified field has changed.
/// </summary> /// </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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Xunit; using Xunit;
@ -252,6 +253,76 @@ namespace Microsoft.AspNetCore.Components.Forms
Assert.True(editContext.IsModified(editContext.Field(nameof(EquatableModel.Property)))); 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> class EquatableModel : IEquatable<EquatableModel>
{ {
public string Property { get; set; } = ""; public string Property { get; set; } = "";

View File

@ -353,7 +353,7 @@ namespace Ignitor
_hubConnection = builder.Build(); _hubConnection = builder.Build();
HubConnection.On<int, string>("JS.AttachComponent", OnAttachComponent); 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<string>("JS.EndInvokeDotNet", OnEndInvokeDotNet);
HubConnection.On<int, byte[]>("JS.RenderBatch", OnRenderBatch); HubConnection.On<int, byte[]>("JS.RenderBatch", OnRenderBatch);
HubConnection.On<string>("JS.Error", OnError); HubConnection.On<string>("JS.Error", OnError);
@ -401,9 +401,9 @@ namespace Ignitor
NextAttachComponentReceived?.Completion?.TrySetResult(call); 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); Operations?.JSInteropCalls.Enqueue(call);
JSInterop?.Invoke(call); JSInterop?.Invoke(call);

View File

@ -5,15 +5,19 @@ namespace Ignitor
{ {
public class CapturedJSInteropCall 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; AsyncHandle = asyncHandle;
Identifier = identifier; Identifier = identifier;
ArgsJson = argsJson; ArgsJson = argsJson;
ResultType = resultType;
TargetInstanceId = targetInstanceId;
} }
public int AsyncHandle { get; } public int AsyncHandle { get; }
public string Identifier { get; } public string Identifier { get; }
public string ArgsJson { 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)); 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) if (_clientProxy is null)
{ {
@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
Log.BeginInvokeJS(_logger, asyncHandle, identifier); 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 public static class Log

View File

@ -59,13 +59,13 @@ namespace Microsoft.AspNetCore.Components.Server
{ {
private readonly IDataProtector _dataProtector; private readonly IDataProtector _dataProtector;
private readonly ILogger<ServerComponentDeserializer> _logger; private readonly ILogger<ServerComponentDeserializer> _logger;
private readonly ServerComponentTypeCache _rootComponentTypeCache; private readonly RootComponentTypeCache _rootComponentTypeCache;
private readonly ComponentParameterDeserializer _parametersDeserializer; private readonly ComponentParameterDeserializer _parametersDeserializer;
public ServerComponentDeserializer( public ServerComponentDeserializer(
IDataProtectionProvider dataProtectionProvider, IDataProtectionProvider dataProtectionProvider,
ILogger<ServerComponentDeserializer> logger, ILogger<ServerComponentDeserializer> logger,
ServerComponentTypeCache rootComponentTypeCache, RootComponentTypeCache rootComponentTypeCache,
ComponentParameterDeserializer parametersDeserializer) ComponentParameterDeserializer parametersDeserializer)
{ {
// When we protect the data we use a time-limited data protector with the // 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.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<StaticFileOptions>, ConfigureStaticFilesOptions>());
services.TryAddSingleton<CircuitFactory>(); services.TryAddSingleton<CircuitFactory>();
services.TryAddSingleton<ServerComponentDeserializer>(); services.TryAddSingleton<ServerComponentDeserializer>();
services.TryAddSingleton<ServerComponentTypeCache>(); services.TryAddSingleton<RootComponentTypeCache>();
services.TryAddSingleton<ComponentParameterDeserializer>(); services.TryAddSingleton<ComponentParameterDeserializer>();
services.TryAddSingleton<ComponentParametersTypeCache>(); services.TryAddSingleton<ComponentParametersTypeCache>();
services.TryAddSingleton<CircuitIdFactory>(); services.TryAddSingleton<CircuitIdFactory>();

View File

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

View File

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

View File

@ -9,7 +9,7 @@ using System.Reflection;
namespace Microsoft.AspNetCore.Components namespace Microsoft.AspNetCore.Components
{ {
// A cache for root component types // A cache for root component types
internal class ServerComponentTypeCache internal class RootComponentTypeCache
{ {
private readonly ConcurrentDictionary<Key, Type> _typeToKeyLookUp = new ConcurrentDictionary<Key, Type>(); 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); 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) => public Key(string assembly, string type) =>
(Assembly, Type) = (assembly, 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); 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 { RenderQueue } from './Platform/Circuits/RenderQueue';
import { ConsoleLogger } from './Platform/Logging/Loggers'; import { ConsoleLogger } from './Platform/Logging/Loggers';
import { LogLevel, Logger } from './Platform/Logging/Logger'; 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 { setEventDispatcher } from './Rendering/RendererEventDispatcher';
import { resolveOptions, CircuitStartOptions } from './Platform/Circuits/CircuitStartOptions'; import { resolveOptions, CircuitStartOptions } from './Platform/Circuits/CircuitStartOptions';
import { DefaultReconnectionHandler } from './Platform/Circuits/DefaultReconnectionHandler'; import { DefaultReconnectionHandler } from './Platform/Circuits/DefaultReconnectionHandler';
import { attachRootComponentToLogicalElement } from './Rendering/Renderer'; import { attachRootComponentToLogicalElement } from './Rendering/Renderer';
import { discoverComponents, ServerComponentDescriptor } from './Services/ComponentDescriptorDiscovery';
let renderingFailed = false; let renderingFailed = false;
let started = false; let started = false;
@ -29,7 +30,7 @@ async function boot(userOptions?: Partial<CircuitStartOptions>): Promise<void> {
options.reconnectionHandler = options.reconnectionHandler || window['Blazor'].defaultReconnectionHandler; options.reconnectionHandler = options.reconnectionHandler || window['Blazor'].defaultReconnectionHandler;
logger.log(LogLevel.Information, 'Starting up blazor server-side application.'); 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 circuit = new CircuitDescriptor(components);
const initialConnection = await initializeConnection(options, logger, circuit); 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.AttachComponent', (componentId, selector) => attachRootComponentToLogicalElement(0, circuit.resolveElement(selector), componentId));
connection.on('JS.BeginInvokeJS', DotNet.jsCallDispatcher.beginInvokeJSFromDotNet); 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); const renderQueue = RenderQueue.getOrCreate(logger);
connection.on('JS.RenderBatch', (batchId: number, batchData: Uint8Array) => { connection.on('JS.RenderBatch', (batchId: number, batchData: Uint8Array) => {

View File

@ -2,7 +2,7 @@ import { DotNet } from '@microsoft/dotnet-js-interop';
import './GlobalExports'; import './GlobalExports';
import * as Environment from './Environment'; import * as Environment from './Environment';
import { monoPlatform } from './Platform/Mono/MonoPlatform'; 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 { SharedMemoryRenderBatch } from './Rendering/RenderBatch/SharedMemoryRenderBatch';
import { shouldAutoStart } from './BootCommon'; import { shouldAutoStart } from './BootCommon';
import { setEventDispatcher } from './Rendering/RendererEventDispatcher'; import { setEventDispatcher } from './Rendering/RendererEventDispatcher';
@ -11,6 +11,8 @@ import { WebAssemblyConfigLoader } from './Platform/WebAssemblyConfigLoader';
import { BootConfigResult } from './Platform/BootConfig'; import { BootConfigResult } from './Platform/BootConfig';
import { Pointer } from './Platform/Platform'; import { Pointer } from './Platform/Platform';
import { WebAssemblyStartOptions } from './Platform/WebAssemblyStartOptions'; import { WebAssemblyStartOptions } from './Platform/WebAssemblyStartOptions';
import { WebAssemblyComponentAttacher } from './Platform/WebAssemblyComponentAttacher';
import { discoverComponents, WebAssemblyComponentDescriptor } from './Services/ComponentDescriptorDiscovery';
let started = false; 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 // Configure environment for execution under Mono WebAssembly with shared-memory rendering
const platform = Environment.setPlatform(monoPlatform); const platform = Environment.setPlatform(monoPlatform);
window['Blazor'].platform = platform; window['Blazor'].platform = platform;
@ -68,8 +73,31 @@ async function boot(options?: Partial<WebAssemblyStartOptions>): Promise<void> {
const environment = options?.environment; const environment = options?.environment;
// Fetch the resources and prepare the Mono runtime // 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([ const [resourceLoader] = await Promise.all([
WebAssemblyResourceLoader.initAsync(bootConfigResult.bootConfig, options || {}), WebAssemblyResourceLoader.initAsync(bootConfigResult.bootConfig, options || {}),
WebAssemblyConfigLoader.initAsync(bootConfigResult)]); WebAssemblyConfigLoader.initAsync(bootConfigResult)]);
@ -84,6 +112,28 @@ async function boot(options?: Partial<WebAssemblyStartOptions>): Promise<void> {
platform.callEntryPoint(resourceLoader.bootConfig.entryAssembly); 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; window['Blazor'].start = boot;
if (shouldAutoStart()) { if (shouldAutoStart()) {
boot().catch(error => { boot().catch(error => {

View File

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

View File

@ -1,12 +1,13 @@
import { internalFunctions as navigationManagerFunctions } from '../../Services/NavigationManager'; import { internalFunctions as navigationManagerFunctions } from '../../Services/NavigationManager';
import { toLogicalRootCommentElement, LogicalElement } from '../../Rendering/LogicalElements'; import { toLogicalRootCommentElement, LogicalElement } from '../../Rendering/LogicalElements';
import { ServerComponentDescriptor } from '../../Services/ComponentDescriptorDiscovery';
export class CircuitDescriptor { export class CircuitDescriptor {
public circuitId?: string; public circuitId?: string;
public components: ComponentDescriptor[]; public components: ServerComponentDescriptor[];
public constructor(components: ComponentDescriptor[]) { public constructor(components: ServerComponentDescriptor[]) {
this.circuitId = undefined; this.circuitId = undefined;
this.components = components; 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: (_) => { }, configureSignalR: (_) => { },
logLevel: LogLevel.Warning, logLevel: LogLevel.Warning,
reconnectionOptions: { reconnectionOptions: {
maxRetries: 5, maxRetries: 8,
retryIntervalMilliseconds: 3000, retryIntervalMilliseconds: 20000,
dialogId: 'components-reconnect-modal', dialogId: 'components-reconnect-modal',
}, },
}; };

View File

@ -12,9 +12,12 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
reloadParagraph: HTMLParagraphElement; 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 = this.document.createElement('div');
this.modal.id = dialogId; this.modal.id = dialogId;
this.maxRetries = maxRetries;
const modalStyles = [ const modalStyles = [
'position: fixed', 'position: fixed',
@ -37,6 +40,9 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
this.message = this.modal.querySelector('h5')!; this.message = this.modal.querySelector('h5')!;
this.button = this.modal.querySelector('button')!; this.button = this.modal.querySelector('button')!;
this.reloadParagraph = this.modal.querySelector('p')!; this.reloadParagraph = this.modal.querySelector('p')!;
this.loader = this.getLoader();
this.message.after(this.loader);
this.button.addEventListener('click', async () => { this.button.addEventListener('click', async () => {
this.show(); this.show();
@ -65,6 +71,7 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
this.document.body.appendChild(this.modal); this.document.body.appendChild(this.modal);
} }
this.modal.style.display = 'block'; this.modal.style.display = 'block';
this.loader.style.display = 'inline-block';
this.button.style.display = 'none'; this.button.style.display = 'none';
this.reloadParagraph.style.display = 'none'; this.reloadParagraph.style.display = 'none';
this.message.textContent = 'Attempting to reconnect to the server...'; this.message.textContent = 'Attempting to reconnect to the server...';
@ -78,6 +85,10 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
}, 0); }, 0);
} }
update(currentAttempt: number): void {
this.message.textContent = `Attempting to reconnect to the server: ${currentAttempt} of ${this.maxRetries}`;
}
hide(): void { hide(): void {
this.modal.style.display = 'none'; this.modal.style.display = 'none';
} }
@ -85,6 +96,7 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
failed(): void { failed(): void {
this.button.style.display = 'block'; this.button.style.display = 'block';
this.reloadParagraph.style.display = 'none'; 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.innerHTML = 'Reconnection failed. Try <a href>reloading</a> the page if you\'re unable to reconnect.';
this.message.querySelector('a')!.addEventListener('click', () => location.reload()); this.message.querySelector('a')!.addEventListener('click', () => location.reload());
} }
@ -92,7 +104,32 @@ export class DefaultReconnectDisplay implements ReconnectDisplay {
rejected(): void { rejected(): void {
this.button.style.display = 'none'; this.button.style.display = 'none';
this.reloadParagraph.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.innerHTML = 'Could not reconnect to the server. <a href>Reload</a> the page to restore functionality.';
this.message.querySelector('a')!.addEventListener('click', () => location.reload()); 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) { if (!this._reconnectionDisplay) {
const modal = document.getElementById(options.dialogId); const modal = document.getElementById(options.dialogId);
this._reconnectionDisplay = modal this._reconnectionDisplay = modal
? new UserSpecifiedDisplay(modal) ? new UserSpecifiedDisplay(modal, options.maxRetries, document)
: new DefaultReconnectDisplay(options.dialogId, document, this._logger); : new DefaultReconnectDisplay(options.dialogId, options.maxRetries, document, this._logger);
} }
if (!this._currentReconnectionProcess) { if (!this._currentReconnectionProcess) {
@ -38,6 +38,8 @@ export class DefaultReconnectionHandler implements ReconnectionHandler {
}; };
class ReconnectionProcess { class ReconnectionProcess {
static readonly MaximumFirstRetryInterval = 3000;
readonly reconnectDisplay: ReconnectDisplay; readonly reconnectDisplay: ReconnectDisplay;
isDisposed = false; isDisposed = false;
@ -54,7 +56,13 @@ class ReconnectionProcess {
async attemptPeriodicReconnection(options: ReconnectionOptions) { async attemptPeriodicReconnection(options: ReconnectionOptions) {
for (let i = 0; i < options.maxRetries; i++) { 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) { if (this.isDisposed) {
break; break;
} }

View File

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

View File

@ -8,7 +8,18 @@ export class UserSpecifiedDisplay implements ReconnectDisplay {
static readonly RejectedClassName = 'components-reconnect-rejected'; 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 { show(): void {
@ -16,6 +27,14 @@ export class UserSpecifiedDisplay implements ReconnectDisplay {
this.dialog.classList.add(UserSpecifiedDisplay.ShowClassName); 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 { hide(): void {
this.removeClasses(); this.removeClasses();
this.dialog.classList.add(UserSpecifiedDisplay.HideClassName); 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; return;
} }
const spacerSeparation = spacerAfter.offsetTop - (spacerBefore.offsetTop + spacerBefore.offsetHeight);
const containerSize = entry.rootBounds?.height; const containerSize = entry.rootBounds?.height;
if (entry.target === spacerBefore) { 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) { } 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 // 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 // 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. // 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'; import { NullLogger } from '../src/Platform/Logging/Loggers';
describe('DefaultReconnectDisplay', () => { 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', () => { it ('adds element to the body on show', () => {
const testDocument = new JSDOM().window.document; const display = new DefaultReconnectDisplay('test-dialog-id', 6, testDocument, NullLogger.instance);
const display = new DefaultReconnectDisplay('test-dialog-id', testDocument, NullLogger.instance);
display.show(); display.show();
@ -16,6 +24,7 @@ describe('DefaultReconnectDisplay', () => {
expect(element!.style.display).toBe('block'); expect(element!.style.display).toBe('block');
expect(element!.style.visibility).toBe('hidden'); 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.message.textContent).toBe('Attempting to reconnect to the server...');
expect(display.button.style.display).toBe('none'); expect(display.button.style.display).toBe('none');
@ -27,8 +36,7 @@ describe('DefaultReconnectDisplay', () => {
}); });
it ('does not add element to the body multiple times', () => { it ('does not add element to the body multiple times', () => {
const testDocument = new JSDOM().window.document; const display = new DefaultReconnectDisplay('test-dialog-id', 6, testDocument, NullLogger.instance);
const display = new DefaultReconnectDisplay('test-dialog-id', testDocument, NullLogger.instance);
display.show(); display.show();
display.show(); display.show();
@ -37,8 +45,7 @@ describe('DefaultReconnectDisplay', () => {
}); });
it ('hides element', () => { it ('hides element', () => {
const testDocument = new JSDOM().window.document; const display = new DefaultReconnectDisplay('test-dialog-id', 6, testDocument, NullLogger.instance);
const display = new DefaultReconnectDisplay('test-dialog-id', testDocument, NullLogger.instance);
display.hide(); display.hide();
@ -46,8 +53,7 @@ describe('DefaultReconnectDisplay', () => {
}); });
it ('updates message on fail', () => { it ('updates message on fail', () => {
const testDocument = new JSDOM().window.document; const display = new DefaultReconnectDisplay('test-dialog-id', 6, testDocument, NullLogger.instance);
const display = new DefaultReconnectDisplay('test-dialog-id', testDocument, NullLogger.instance);
display.show(); display.show();
display.failed(); display.failed();
@ -55,11 +61,11 @@ describe('DefaultReconnectDisplay', () => {
expect(display.modal.style.display).toBe('block'); 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.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.button.style.display).toBe('block');
expect(display.loader.style.display).toBe('none');
}); });
it ('updates message on refused', () => { it ('updates message on refused', () => {
const testDocument = new JSDOM().window.document; const display = new DefaultReconnectDisplay('test-dialog-id', 6, testDocument, NullLogger.instance);
const display = new DefaultReconnectDisplay('test-dialog-id', testDocument, NullLogger.instance);
display.show(); display.show();
display.rejected(); display.rejected();
@ -67,6 +73,18 @@ describe('DefaultReconnectDisplay', () => {
expect(display.modal.style.display).toBe('block'); 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.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.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(testDisplay.failed).toHaveBeenCalled();
expect(reconnect).toHaveBeenCalledTimes(2); 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 { function attachUserSpecifiedUI(options: ReconnectionOptions): Element {
@ -92,6 +109,7 @@ function delay(durationMilliseconds: number) {
function createTestDisplay(): ReconnectDisplay { function createTestDisplay(): ReconnectDisplay {
return { return {
show: jest.fn(), show: jest.fn(),
update: jest.fn(),
hide: jest.fn(), hide: jest.fn(),
failed: jest.fn(), failed: jest.fn(),
rejected: 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
namespace Microsoft.AspNetCore.Components.Forms namespace Microsoft.AspNetCore.Components.Forms
@ -13,6 +12,8 @@ namespace Microsoft.AspNetCore.Components.Forms
/// </summary> /// </summary>
public static class EditContextFieldClassExtensions public static class EditContextFieldClassExtensions
{ {
private readonly static object FieldCssClassProviderKey = new object();
/// <summary> /// <summary>
/// Gets a string that indicates the status of the specified field as a CSS class. This will include /// 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. /// 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)); => FieldCssClass(editContext, FieldIdentifier.Create(accessor));
/// <summary> /// <summary>
/// Gets a string that indicates the status of the specified field as a CSS class. This will include /// Gets a string that indicates the status of the specified field as a CSS class.
/// some combination of "modified", "valid", or "invalid", depending on the status of the field.
/// </summary> /// </summary>
/// <param name="editContext">The <see cref="EditContext"/>.</param> /// <param name="editContext">The <see cref="EditContext"/>.</param>
/// <param name="fieldIdentifier">An identifier for the field.</param> /// <param name="fieldIdentifier">An identifier for the field.</param>
/// <returns>A string that indicates the status of the field.</returns> /// <returns>A string that indicates the status of the field.</returns>
public static string FieldCssClass(this EditContext editContext, in FieldIdentifier fieldIdentifier) public static string FieldCssClass(this EditContext editContext, in FieldIdentifier fieldIdentifier)
{ {
var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any(); var provider = editContext.Properties.TryGetValue(FieldCssClassProviderKey, out var customProvider)
if (editContext.IsModified(fieldIdentifier)) ? (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"; throw new ArgumentNullException(nameof(fieldCssClassProvider));
}
else
{
return isValid ? "valid" : "invalid";
} }
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 internal interface IVirtualizeJsCallbacks
{ {
void OnBeforeSpacerVisible(float spacerSize, float containerSize); void OnBeforeSpacerVisible(float spacerSize, float spacerSeparation, float containerSize);
void OnAfterSpacerVisible(float spacerSize, float containerSize); void OnAfterSpacerVisible(float spacerSize, float spacerSeparation, float containerSize);
} }
} }

View File

@ -13,13 +13,24 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
/// </summary> /// </summary>
public int Index { get; } 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> /// <summary>
/// Constructs a new <see cref="PlaceholderContext"/> instance. /// Constructs a new <see cref="PlaceholderContext"/> instance.
/// </summary> /// </summary>
/// <param name="index">The item index of the placeholder.</param> /// <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; Index = index;
Size = size;
} }
} }
} }

View File

@ -31,6 +31,12 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
private int _loadedItemsStartIndex; private int _loadedItemsStartIndex;
private int _lastRenderedItemCount;
private int _lastRenderedPlaceholderCount;
private float _itemSize;
private IEnumerable<TItem>? _loadedItems; private IEnumerable<TItem>? _loadedItems;
private CancellationTokenSource? _refreshCts; private CancellationTokenSource? _refreshCts;
@ -65,10 +71,10 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
public RenderFragment<PlaceholderContext>? Placeholder { get; set; } public RenderFragment<PlaceholderContext>? Placeholder { get; set; }
/// <summary> /// <summary>
/// Gets the size of each item in pixels. /// Gets the size of each item in pixels. Defaults to 50px.
/// </summary> /// </summary>
[Parameter] [Parameter]
public float ItemSize { get; set; } public float ItemSize { get; set; } = 50f;
/// <summary> /// <summary>
/// Gets or sets the function providing items to the list. /// Gets or sets the function providing items to the list.
@ -88,7 +94,12 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
if (ItemSize <= 0) if (ItemSize <= 0)
{ {
throw new InvalidOperationException( 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) 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 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. // 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(); builder.CloseRegion();
_lastRenderedItemCount = 0;
// Render the loaded items. // Render the loaded items.
if (_loadedItems != null && _itemTemplate != null) if (_loadedItems != null && _itemTemplate != null)
{ {
@ -171,18 +184,22 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
foreach (var item in itemsToShow) foreach (var item in itemsToShow)
{ {
_itemTemplate(item)(builder); _itemTemplate(item)(builder);
renderIndex++; _lastRenderedItemCount++;
} }
renderIndex += _lastRenderedItemCount;
builder.CloseRegion(); builder.CloseRegion();
} }
_lastRenderedPlaceholderCount = Math.Max(0, lastItemIndex - _itemsBefore - _lastRenderedItemCount);
builder.OpenRegion(5); builder.OpenRegion(5);
// Render the placeholders after the loaded items. // Render the placeholders after the loaded items.
for (; renderIndex < lastItemIndex; renderIndex++) for (; renderIndex < lastItemIndex; renderIndex++)
{ {
builder.AddContent(renderIndex, _placeholder, new PlaceholderContext(renderIndex)); builder.AddContent(renderIndex, _placeholder, new PlaceholderContext(renderIndex, _itemSize));
} }
builder.CloseRegion(); builder.CloseRegion();
@ -197,28 +214,45 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
} }
private string GetSpacerStyle(int itemsInSpacer) 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); 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); var itemsBefore = Math.Max(0, _itemCount - itemsAfter - visibleItemCapacity);
UpdateItemDistribution(itemsBefore, 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); if (_lastRenderedItemCount > 0)
visibleItemCapacity = (int)Math.Ceiling(containerSize / ItemSize) + 2; {
_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) private void UpdateItemDistribution(int itemsBefore, int visibleItemCapacity)
@ -285,7 +319,7 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
private RenderFragment DefaultPlaceholder(PlaceholderContext context) => (builder) => private RenderFragment DefaultPlaceholder(PlaceholderContext context) => (builder) =>
{ {
builder.OpenElement(0, "div"); builder.OpenElement(0, "div");
builder.AddAttribute(1, "style", $"height: {ItemSize}px;"); builder.AddAttribute(1, "style", $"height: {_itemSize}px;");
builder.CloseElement(); builder.CloseElement();
}; };

View File

@ -30,15 +30,15 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization
} }
[JSInvokable] [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] [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() public async ValueTask DisposeAsync()

View File

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

View File

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

View File

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

View File

@ -2,6 +2,20 @@
# yarn lockfile v1 # 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": "@webassemblyjs/ast@1.8.5":
version "1.8.5" version "1.8.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" 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: dependencies:
ms "2.0.0" 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: decamelize@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 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" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
msal@^1.2.1: ms@^2.1.1:
version "1.2.1" version "2.1.2"
resolved "https://registry.yarnpkg.com/msal/-/msal-1.2.1.tgz#08133e37ab0b9741866c89a3fadc55aadb980723" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-Zo28eyRtT/Un+zcpMfPtTPD+eo/OqzsRER0k5dyk8Mje/K1oLlaEOAgZHlJs59Y2xyuVg8OrcKqSn/1MeNjZYw== integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
dependencies:
tslib "^1.9.3"
nan@^2.12.1: nan@^2.12.1:
version "2.14.0" version "2.14.0"
@ -2485,7 +2504,7 @@ ts-loader@^6.2.1:
micromatch "^4.0.0" micromatch "^4.0.0"
semver "^6.0.0" semver "^6.0.0"
tslib@^1.9.0, tslib@^1.9.3: tslib@^1.9.0:
version "1.10.0" version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
namespace Microsoft.Authentication.WebAssembly.Msal 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. /// Gets or sets whether or not to navigate to the login request url after a successful login.
/// </summary> /// </summary>
public bool NavigateToLoginRequestUrl { get; set; } = false; 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> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<!-- Set this to false because assemblies should not reference this assembly directly, (except for tests, of course). --> <!-- Set this to false because assemblies should not reference this assembly directly, (except for tests, of course). -->
<IsProjectReferenceProvider>false</IsProjectReferenceProvider> <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> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.AspNetCore" /> <FrameworkReference Include="Microsoft.AspNetCore.App" />
<Reference Include="Microsoft.AspNetCore.Diagnostics" />
<Reference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" />
<Reference Include="Microsoft.AspNetCore.Components.Server" />
<Reference Include="Microsoft.AspNetCore.ResponseCompression" />
<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" /> <Compile Include="$(SharedSourceRoot)CommandLineUtils\**\*.cs" />
<Reference Include="Microsoft.Extensions.Hosting" />
</ItemGroup> </ItemGroup>
<!-- Pack settings --> <!-- Pack settings -->
@ -36,19 +45,5 @@
<NuspecProperty Include="PackageThirdPartyNoticesFile=$(PackageThirdPartyNoticesFile)" /> <NuspecProperty Include="PackageThirdPartyNoticesFile=$(PackageThirdPartyNoticesFile)" />
</ItemGroup> </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> </Project>

View File

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

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 /// Provides methods for invoking JavaScript functions for applications running
/// on the Mono WebAssembly runtime. /// on the Mono WebAssembly runtime.
/// </summary> /// </summary>
public abstract class WebAssemblyJSRuntime : JSInProcessRuntime public abstract class WebAssemblyJSRuntime : JSInProcessRuntime, IJSUnmarshalledRuntime
{ {
/// <inheritdoc /> /// <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 callInfo = new JSCallInfo
var result = InternalCalls.InvokeJSMarshalled(out var exception, ref noAsyncHandle, identifier, argsJson); {
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 return exception != null
? throw new JSException(exception) ? throw new JSException(exception)
: result; : result;
} }
/// <inheritdoc /> /// <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) 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 // 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) // 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); 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> /// <inheritdoc />
/// Invokes the JavaScript function registered with the specified identifier. TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<TResult>(string identifier)
/// </summary> => ((IJSUnmarshalledRuntime)this).InvokeUnmarshalled<object, object, object, TResult>(identifier, null, null, null);
/// <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);
/// <summary> /// <inheritdoc />
/// Invokes the JavaScript function registered with the specified identifier. TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<T0, TResult>(string identifier, T0 arg0)
/// </summary> => ((IJSUnmarshalledRuntime)this).InvokeUnmarshalled<T0, object, object, TResult>(identifier, arg0, null, null);
/// <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);
/// <summary> /// <inheritdoc />
/// Invokes the JavaScript function registered with the specified identifier. TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<T0, T1, TResult>(string identifier, T0 arg0, T1 arg1)
/// </summary> => ((IJSUnmarshalledRuntime)this).InvokeUnmarshalled<T0, T1, object, TResult>(identifier, arg0, arg1, null);
/// <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);
/// <summary> /// <inheritdoc />
/// Invokes the JavaScript function registered with the specified identifier. TResult IJSUnmarshalledRuntime.InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
/// </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)
{ {
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 return exception != null
? throw new JSException(exception) ? throw new JSException(exception)
: result; : result;

View File

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

View File

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

View File

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

View File

@ -41,6 +41,8 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
// Verify web.config // Verify web.config
Assert.FileExists(result, publishDirectory, "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); Assert.FileCountEquals(result, 1, publishDirectory, "*", SearchOption.TopDirectoryOnly);
VerifyBootManifestHashes(result, blazorPublishDirectory); VerifyBootManifestHashes(result, blazorPublishDirectory);
@ -141,11 +143,10 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"), serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
serviceWorkerContent: "// This is the production service worker", serviceWorkerContent: "// This is the production service worker",
assetsManifestPath: "custom-service-worker-assets.js"); assetsManifestPath: "custom-service-worker-assets.js");
VerifyTypeGranularTrimming(result, blazorPublishDirectory);
} }
[Fact] [Fact]
[QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/23756")]
public async Task Publish_InRelease_Works() public async Task Publish_InRelease_Works()
{ {
// Arrange // Arrange
@ -434,7 +435,8 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
Assert.Contains("System.Text.Json.dll", assemblies); Assert.Contains("System.Text.Json.dll", assemblies);
// No pdbs // 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.Null(bootJsonData.resources.satelliteResources);
Assert.Contains("appsettings.json", bootJsonData.config); Assert.Contains("appsettings.json", bootJsonData.config);
@ -906,16 +908,17 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
private void VerifyTypeGranularTrimming(MSBuildResult result, string blazorPublishDirectory) private void VerifyTypeGranularTrimming(MSBuildResult result, string blazorPublishDirectory)
{ {
var loggingAssemblyPath = Path.Combine(blazorPublishDirectory, "_framework", "Microsoft.Extensions.Logging.Abstractions.dll"); var componentsShimAssemblyPath = Path.Combine(blazorPublishDirectory, "_framework", "Microsoft.AspNetCore.Razor.Test.ComponentShim.dll");
Assert.FileExists(result, loggingAssemblyPath); Assert.FileExists(result, componentsShimAssemblyPath);
// ILogger is referenced by the app, so we expect it to be preserved // RouteView is referenced by the app, so we expect it to be preserved
Assert.AssemblyContainsType(result, loggingAssemblyPath, "Microsoft.Extensions.Logging.ILogger"); Assert.AssemblyContainsType(result, componentsShimAssemblyPath, "Microsoft.AspNetCore.Components.RouteView");
// LogLevel is referenced by ILogger and therefore must be preserved.
Assert.AssemblyContainsType(result, loggingAssemblyPath, "Microsoft.Extensions.Logging.LogLevel");
// NullLogger is not referenced by the app, and should be trimmed. // RouteData is referenced by RouteView so we expect it to be preserved.
Assert.AssemblyDoesNotContainType(result, loggingAssemblyPath, "Microsoft.Extensions.Logging.Abstractions.NullLogger"); 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) 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() protected override string GenerateResponseFileCommands()
{ {

View File

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

View File

@ -53,6 +53,14 @@ Copyright (c) .NET Foundation. All rights reserved.
<!-- Trimmer defaults --> <!-- Trimmer defaults -->
<PublishTrimmed Condition="'$(PublishTrimmed)' == ''">true</PublishTrimmed> <PublishTrimmed Condition="'$(PublishTrimmed)' == ''">true</PublishTrimmed>
<TrimMode Condition="'$(TrimMode)' == ''">link</TrimMode> <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> <StaticWebAssetBasePath Condition="'$(StaticWebAssetBasePath)' == ''">/</StaticWebAssetBasePath>
<BlazorCacheBootResources Condition="'$(BlazorCacheBootResources)' == ''">true</BlazorCacheBootResources> <BlazorCacheBootResources Condition="'$(BlazorCacheBootResources)' == ''">true</BlazorCacheBootResources>
@ -69,6 +77,12 @@ Copyright (c) .NET Foundation. All rights reserved.
</PropertyGroup> </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)' != ''" /> <Import Project="Microsoft.NET.Sdk.BlazorWebAssembly.ServiceWorkerAssetsManifest.targets" Condition="'$(ServiceWorkerAssetsManifest)' != ''" />
<Target Name="_ScrambleDotnetJsFileName" AfterTargets="ResolveRuntimePackAssets"> <Target Name="_ScrambleDotnetJsFileName" AfterTargets="ResolveRuntimePackAssets">
@ -395,7 +409,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<ItemGroup> <ItemGroup>
<_BlazorTypeGranularAssembly <_BlazorTypeGranularAssembly
Include="@(ManagedAssemblyToLink)" 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> <Required>false</Required>
<Preserve>all</Preserve> <Preserve>all</Preserve>
</_BlazorTypeGranularAssembly> </_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/'))" /> Condition="'%(ResolvedFileToPublish.RelativePath)' != 'web.config' AND !$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))" />
<!-- Remove pdbs from the publish output --> <!-- 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>
<ItemGroup Condition="'@(ResolvedFileToPublish->AnyHaveMetadataValue('RelativePath', 'web.config'))' != 'true'"> <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(System.Text.Json.JsonSerializer));
GC.KeepAlive(typeof(RazorClassLibrary.Class1)); GC.KeepAlive(typeof(RazorClassLibrary.Class1));
GC.KeepAlive(typeof(Microsoft.Extensions.Logging.ILogger));
#if REFERENCE_classlibrarywithsatelliteassemblies #if REFERENCE_classlibrarywithsatelliteassemblies
GC.KeepAlive(typeof(classlibrarywithsatelliteassemblies.Class1)); GC.KeepAlive(typeof(classlibrarywithsatelliteassemblies.Class1));
#endif #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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
@ -16,7 +17,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
/// and <paramref name="selector"/>. /// and <paramref name="selector"/>.
/// </summary> /// </summary>
/// <param name="componentType">The component type. Must implement <see cref="IComponent"/>.</param> /// <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) public RootComponentMapping(Type componentType, string selector)
{ {
if (componentType is null) if (componentType is null)
@ -38,6 +39,19 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
ComponentType = componentType; ComponentType = componentType;
Selector = selector; 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> /// <summary>
@ -49,5 +63,10 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
/// Gets the DOM element selector. /// Gets the DOM element selector.
/// </summary> /// </summary>
public string Selector { get; } 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="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.</param>
public void Add(Type componentType, string selector) 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) if (componentType is null)
{ {
@ -45,7 +56,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
throw new ArgumentNullException(nameof(selector)); throw new ArgumentNullException(nameof(selector));
} }
Add(new RootComponentMapping(componentType, selector)); Add(new RootComponentMapping(componentType, selector, parameters));
} }
/// <summary> /// <summary>

View File

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

View File

@ -21,6 +21,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
public sealed class WebAssemblyHostBuilder public sealed class WebAssemblyHostBuilder
{ {
private Func<IServiceProvider> _createServiceProvider; private Func<IServiceProvider> _createServiceProvider;
private RootComponentTypeCache _rootComponentCache;
/// <summary> /// <summary>
/// Creates an instance of <see cref="WebAssemblyHostBuilder"/> using the most common /// 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 // Retrieve required attributes from JSRuntimeInvoker
InitializeNavigationManager(jsRuntimeInvoker); InitializeNavigationManager(jsRuntimeInvoker);
InitializeRegisteredRootComponents(jsRuntimeInvoker);
InitializeDefaultServices(); InitializeDefaultServices();
var hostEnvironment = InitializeEnvironment(jsRuntimeInvoker); 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) private void InitializeNavigationManager(WebAssemblyJSRuntimeInvoker jsRuntimeInvoker)
{ {
var baseUri = jsRuntimeInvoker.InvokeUnmarshalled<object, object, object, string>(BrowserNavigationManagerInterop.GetBaseUri, null, null, null); 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<NavigationManager>(WebAssemblyNavigationManager.Instance);
Services.AddSingleton<INavigationInterception>(WebAssemblyNavigationInterception.Instance); Services.AddSingleton<INavigationInterception>(WebAssemblyNavigationInterception.Instance);
Services.AddSingleton(new LazyAssemblyLoader(DefaultWebAssemblyJSRuntime.Instance)); Services.AddSingleton(new LazyAssemblyLoader(DefaultWebAssemblyJSRuntime.Instance));
Services.AddLogging(builder => { Services.AddLogging(builder =>
{
builder.AddProvider(new WebAssemblyConsoleLoggerProvider(DefaultWebAssemblyJSRuntime.Instance)); builder.AddProvider(new WebAssemblyConsoleLoggerProvider(DefaultWebAssemblyJSRuntime.Instance));
}); });
} }

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework> <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
@ -15,13 +15,7 @@
<Reference Include="Microsoft.Extensions.Logging" /> <Reference Include="Microsoft.Extensions.Logging" />
<Reference Include="Microsoft.JSInterop.WebAssembly" /> <Reference Include="Microsoft.JSInterop.WebAssembly" />
<ProjectReference <ProjectReference Include="..\..\..\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj" ReferenceOutputAssemblies="false" SkipGetTargetFrameworkProperties="true" UndefineProperties="TargetFramework" Private="false" Condition="'$(BuildNodeJS)' != 'false' and '$(BuildingInsideVisualStudio)' != 'true'" />
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" /> <SuppressBaselineReference Include="Microsoft.AspNetCore.Components.WebAssembly.HttpHandler" />
</ItemGroup> </ItemGroup>
@ -31,6 +25,11 @@
<Compile Include="$(ComponentsSharedSourceRoot)src\JsonSerializerOptionsProvider.cs" /> <Compile Include="$(ComponentsSharedSourceRoot)src\JsonSerializerOptionsProvider.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\WebEventData.cs" /> <Compile Include="$(ComponentsSharedSourceRoot)src\WebEventData.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\ElementReferenceJsonConverter.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>
<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.RenderTree;
using Microsoft.AspNetCore.Components.WebAssembly.Services; using Microsoft.AspNetCore.Components.WebAssembly.Services;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.JSInterop;
using Microsoft.JSInterop.WebAssembly; using Microsoft.JSInterop.WebAssembly;
namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering
@ -46,13 +47,14 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering
/// </summary> /// </summary>
/// <typeparam name="TComponent">The type of the component.</typeparam> /// <typeparam name="TComponent">The type of the component.</typeparam>
/// <param name="domElementSelector">A CSS selector that uniquely identifies a DOM element.</param> /// <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> /// <returns>A <see cref="Task"/> that represents the asynchronous rendering of the added component.</returns>
/// <remarks> /// <remarks>
/// Callers of this method may choose to ignore the returned <see cref="Task"/> if they do not /// 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. /// want to await the rendering of the added component.
/// </remarks> /// </remarks>
public Task AddComponentAsync<TComponent>(string domElementSelector) where TComponent : IComponent public Task AddComponentAsync<TComponent>(string domElementSelector, ParameterView parameters) where TComponent : IComponent
=> AddComponentAsync(typeof(TComponent), domElementSelector); => AddComponentAsync(typeof(TComponent), domElementSelector, parameters);
/// <summary> /// <summary>
/// Associates the <see cref="IComponent"/> with the <see cref="WebAssemblyRenderer"/>, /// Associates the <see cref="IComponent"/> with the <see cref="WebAssemblyRenderer"/>,
@ -60,12 +62,13 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering
/// </summary> /// </summary>
/// <param name="componentType">The type of the component.</param> /// <param name="componentType">The type of the component.</param>
/// <param name="domElementSelector">A CSS selector that uniquely identifies a DOM element.</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> /// <returns>A <see cref="Task"/> that represents the asynchronous rendering of the added component.</returns>
/// <remarks> /// <remarks>
/// Callers of this method may choose to ignore the returned <see cref="Task"/> if they do not /// 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. /// want to await the rendering of the added component.
/// </remarks> /// </remarks>
public Task AddComponentAsync(Type componentType, string domElementSelector) public Task AddComponentAsync(Type componentType, string domElementSelector, ParameterView parameters)
{ {
var component = InstantiateComponent(componentType); var component = InstantiateComponent(componentType);
var componentId = AssignRootComponentId(component); var componentId = AssignRootComponentId(component);
@ -82,7 +85,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering
componentId, componentId,
_webAssemblyRendererId); _webAssemblyRendererId);
return RenderRootComponentAsync(componentId); return RenderRootComponentAsync(componentId, parameters);
} }
/// <inheritdoc /> /// <inheritdoc />
@ -95,7 +98,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering
/// <inheritdoc /> /// <inheritdoc />
protected override Task UpdateDisplayAsync(in RenderBatch batch) protected override Task UpdateDisplayAsync(in RenderBatch batch)
{ {
DefaultWebAssemblyJSRuntime.Instance.InvokeUnmarshalled<int, RenderBatch, object>( ((IJSUnmarshalledRuntime)DefaultWebAssemblyJSRuntime.Instance).InvokeUnmarshalled<int, RenderBatch, object>(
"Blazor._internal.renderBatch", "Blazor._internal.renderBatch",
_webAssemblyRendererId, _webAssemblyRendererId,
batch); batch);

View File

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

View File

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

View File

@ -1,13 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // 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 namespace Microsoft.AspNetCore.Components.WebAssembly.Services
{ {
/// <summary> /// <summary>
/// This class exists to enable unit testing for code that needs to call /// 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, /// 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 /// 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 static WebAssemblyJSRuntimeInvoker Instance = new WebAssemblyJSRuntimeInvoker();
public virtual TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2) 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