Merge pull request #24128 from dotnet-maestro-bot/merge/release/5.0-preview8-to-master
[automated] Merge branch 'release/5.0-preview8' => 'master'
This commit is contained in:
commit
088380b45c
|
|
@ -1427,6 +1427,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Compon
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Web.Extensions.Tests", "src\Components\Web.Extensions\test\Microsoft.AspNetCore.Components.Web.Extensions.Tests.csproj", "{157605CB-5170-4C1A-980F-4BAE42DB60DE}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Web.Extensions.Tests", "src\Components\Web.Extensions\test\Microsoft.AspNetCore.Components.Web.Extensions.Tests.csproj", "{157605CB-5170-4C1A-980F-4BAE42DB60DE}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sdk", "Sdk", "{FED4267E-E5E4-49C5-98DB-8B3F203596EE}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.NET.Sdk.BlazorWebAssembly", "src\Components\WebAssembly\Sdk\src\Microsoft.NET.Sdk.BlazorWebAssembly.csproj", "{6B2734BF-C61D-4889-ABBF-456A4075D59B}"
|
||||||
|
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}"
|
||||||
|
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}"
|
||||||
|
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}"
|
||||||
|
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
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicTestApp", "src\Components\test\testassets\BasicTestApp\BasicTestApp.csproj", "{46FB7E93-1294-4068-B80A-D4864F78277A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicTestApp", "src\Components\test\testassets\BasicTestApp\BasicTestApp.csproj", "{46FB7E93-1294-4068-B80A-D4864F78277A}"
|
||||||
|
|
@ -6743,6 +6753,54 @@ Global
|
||||||
{157605CB-5170-4C1A-980F-4BAE42DB60DE}.Release|x64.Build.0 = Release|Any CPU
|
{157605CB-5170-4C1A-980F-4BAE42DB60DE}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{157605CB-5170-4C1A-980F-4BAE42DB60DE}.Release|x86.ActiveCfg = Release|Any CPU
|
{157605CB-5170-4C1A-980F-4BAE42DB60DE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{157605CB-5170-4C1A-980F-4BAE42DB60DE}.Release|x86.Build.0 = Release|Any CPU
|
{157605CB-5170-4C1A-980F-4BAE42DB60DE}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{83371889-9A3E-4D16-AE77-EB4F83BC6374}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{83371889-9A3E-4D16-AE77-EB4F83BC6374}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{83371889-9A3E-4D16-AE77-EB4F83BC6374}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{83371889-9A3E-4D16-AE77-EB4F83BC6374}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{83371889-9A3E-4D16-AE77-EB4F83BC6374}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{83371889-9A3E-4D16-AE77-EB4F83BC6374}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{83371889-9A3E-4D16-AE77-EB4F83BC6374}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{83371889-9A3E-4D16-AE77-EB4F83BC6374}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{83371889-9A3E-4D16-AE77-EB4F83BC6374}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{83371889-9A3E-4D16-AE77-EB4F83BC6374}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{83371889-9A3E-4D16-AE77-EB4F83BC6374}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{83371889-9A3E-4D16-AE77-EB4F83BC6374}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{525EBCB4-A870-470B-BC90-845306C337D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{525EBCB4-A870-470B-BC90-845306C337D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{525EBCB4-A870-470B-BC90-845306C337D1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{525EBCB4-A870-470B-BC90-845306C337D1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{525EBCB4-A870-470B-BC90-845306C337D1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{525EBCB4-A870-470B-BC90-845306C337D1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{525EBCB4-A870-470B-BC90-845306C337D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{525EBCB4-A870-470B-BC90-845306C337D1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{525EBCB4-A870-470B-BC90-845306C337D1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{525EBCB4-A870-470B-BC90-845306C337D1}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{525EBCB4-A870-470B-BC90-845306C337D1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{525EBCB4-A870-470B-BC90-845306C337D1}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{175E5CD8-92D4-46BB-882E-3A930D3302D4}.Release|x64.ActiveCfg = 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.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
|
||||||
|
|
@ -7530,6 +7588,11 @@ Global
|
||||||
{F71FE795-9923-461B-9809-BB1821A276D0} = {60D51C98-2CC0-40DF-B338-44154EFEE2FF}
|
{F71FE795-9923-461B-9809-BB1821A276D0} = {60D51C98-2CC0-40DF-B338-44154EFEE2FF}
|
||||||
{8294A74F-7DAA-4B69-BC56-7634D93C9693} = {F71FE795-9923-461B-9809-BB1821A276D0}
|
{8294A74F-7DAA-4B69-BC56-7634D93C9693} = {F71FE795-9923-461B-9809-BB1821A276D0}
|
||||||
{157605CB-5170-4C1A-980F-4BAE42DB60DE} = {F71FE795-9923-461B-9809-BB1821A276D0}
|
{157605CB-5170-4C1A-980F-4BAE42DB60DE} = {F71FE795-9923-461B-9809-BB1821A276D0}
|
||||||
|
{FED4267E-E5E4-49C5-98DB-8B3F203596EE} = {562D5067-8CD8-4F19-BCBB-873204932C61}
|
||||||
|
{6B2734BF-C61D-4889-ABBF-456A4075D59B} = {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}
|
||||||
|
{175E5CD8-92D4-46BB-882E-3A930D3302D4} = {FED4267E-E5E4-49C5-98DB-8B3F203596EE}
|
||||||
{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}
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,7 @@
|
||||||
@(ProjectToBuild);
|
@(ProjectToBuild);
|
||||||
@(ProjectToExclude);
|
@(ProjectToExclude);
|
||||||
$(RepoRoot)src\Razor\test\testassets\**\*.*proj;
|
$(RepoRoot)src\Razor\test\testassets\**\*.*proj;
|
||||||
|
$(RepoRoot)src\Components\WebAssembly\Sdk\testassets\**\*.*proj;
|
||||||
$(RepoRoot)**\node_modules\**\*;
|
$(RepoRoot)**\node_modules\**\*;
|
||||||
$(RepoRoot)**\bin\**\*;
|
$(RepoRoot)**\bin\**\*;
|
||||||
$(RepoRoot)**\obj\**\*;"
|
$(RepoRoot)**\obj\**\*;"
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,7 @@
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.Web.Extensions" ProjectPath="$(RepoRoot)src\Components\Web.Extensions\src\Microsoft.AspNetCore.Components.Web.Extensions.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.Web.Extensions" ProjectPath="$(RepoRoot)src\Components\Web.Extensions\src\Microsoft.AspNetCore.Components.Web.Extensions.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.Authentication.WebAssembly.Msal" ProjectPath="$(RepoRoot)src\Components\WebAssembly\Authentication.Msal\src\Microsoft.Authentication.WebAssembly.Msal.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.Authentication.WebAssembly.Msal" ProjectPath="$(RepoRoot)src\Components\WebAssembly\Authentication.Msal\src\Microsoft.Authentication.WebAssembly.Msal.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.JSInterop.WebAssembly" ProjectPath="$(RepoRoot)src\Components\WebAssembly\JSInterop\src\Microsoft.JSInterop.WebAssembly.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.JSInterop.WebAssembly" ProjectPath="$(RepoRoot)src\Components\WebAssembly\JSInterop\src\Microsoft.JSInterop.WebAssembly.csproj" />
|
||||||
|
<ProjectReferenceProvider Include="Microsoft.NET.Sdk.BlazorWebAssembly" ProjectPath="$(RepoRoot)src\Components\WebAssembly\Sdk\src\Microsoft.NET.Sdk.BlazorWebAssembly.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebAssembly.Server" ProjectPath="$(RepoRoot)src\Components\WebAssembly\Server\src\Microsoft.AspNetCore.Components.WebAssembly.Server.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebAssembly.Server" ProjectPath="$(RepoRoot)src\Components\WebAssembly\Server\src\Microsoft.AspNetCore.Components.WebAssembly.Server.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" ProjectPath="$(RepoRoot)src\Components\WebAssembly\WebAssembly.Authentication\src\Microsoft.AspNetCore.Components.WebAssembly.Authentication.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" ProjectPath="$(RepoRoot)src\Components\WebAssembly\WebAssembly.Authentication\src\Microsoft.AspNetCore.Components.WebAssembly.Authentication.csproj" />
|
||||||
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebAssembly" ProjectPath="$(RepoRoot)src\Components\WebAssembly\WebAssembly\src\Microsoft.AspNetCore.Components.WebAssembly.csproj" />
|
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebAssembly" ProjectPath="$(RepoRoot)src\Components\WebAssembly\WebAssembly\src\Microsoft.AspNetCore.Components.WebAssembly.csproj" />
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,9 @@
|
||||||
"src\\Components\\WebAssembly\\WebAssembly.Authentication\\test\\Microsoft.AspNetCore.Components.WebAssembly.Authentication.Tests.csproj",
|
"src\\Components\\WebAssembly\\WebAssembly.Authentication\\test\\Microsoft.AspNetCore.Components.WebAssembly.Authentication.Tests.csproj",
|
||||||
"src\\Components\\WebAssembly\\testassets\\Wasm.Authentication.Client\\Wasm.Authentication.Client.csproj",
|
"src\\Components\\WebAssembly\\testassets\\Wasm.Authentication.Client\\Wasm.Authentication.Client.csproj",
|
||||||
"src\\Components\\WebAssembly\\testassets\\Wasm.Authentication.Shared\\Wasm.Authentication.Shared.csproj",
|
"src\\Components\\WebAssembly\\testassets\\Wasm.Authentication.Shared\\Wasm.Authentication.Shared.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\\integrationtests\\Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests.csproj",
|
||||||
"src\\JSInterop\\Microsoft.JSInterop\\src\\Microsoft.JSInterop.csproj"
|
"src\\JSInterop\\Microsoft.JSInterop\\src\\Microsoft.JSInterop.csproj"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#nullable disable warnings
|
#nullable disable warnings
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.ExceptionServices;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -72,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 EventCallback<NavigationContext> OnNavigateAsync { get; set; }
|
[Parameter] public Func<NavigationContext, Task> OnNavigateAsync { get; set; }
|
||||||
|
|
||||||
private RouteTable Routes { get; set; }
|
private RouteTable Routes { get; set; }
|
||||||
|
|
||||||
|
|
@ -194,51 +195,58 @@ namespace Microsoft.AspNetCore.Components.Routing
|
||||||
|
|
||||||
private async ValueTask<bool> RunOnNavigateAsync(string path, Task previousOnNavigate)
|
private async ValueTask<bool> RunOnNavigateAsync(string path, Task previousOnNavigate)
|
||||||
{
|
{
|
||||||
// If this router instance does not provide an OnNavigateAsync parameter
|
if (OnNavigateAsync == null)
|
||||||
// then we render the component associated with the route as per usual.
|
|
||||||
if (!OnNavigateAsync.HasDelegate)
|
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we've already invoked a task and stored its CTS, then
|
// Cancel the CTS instead of disposing it, since disposing does not
|
||||||
// cancel that existing CTS.
|
// actually cancel and can cause unintended Object Disposed Exceptions.
|
||||||
|
// This effectivelly cancels the previously running task and completes it.
|
||||||
_onNavigateCts?.Cancel();
|
_onNavigateCts?.Cancel();
|
||||||
// Then make sure that the task has been completed cancelled or
|
// Then make sure that the task has been completely cancelled or completed
|
||||||
// completed before continuing with the execution of this current task.
|
// before starting the next one. This avoid race conditions where the cancellation
|
||||||
|
// for the previous task was set but not fully completed by the time we get to this
|
||||||
|
// invocation.
|
||||||
await previousOnNavigate;
|
await previousOnNavigate;
|
||||||
|
|
||||||
// Create a new cancellation token source for this instance
|
|
||||||
_onNavigateCts = new CancellationTokenSource();
|
_onNavigateCts = new CancellationTokenSource();
|
||||||
var navigateContext = new NavigationContext(path, _onNavigateCts.Token);
|
var navigateContext = new NavigationContext(path, _onNavigateCts.Token);
|
||||||
|
|
||||||
// Create a cancellation task based on the cancellation token
|
try
|
||||||
// associated with the current running task.
|
|
||||||
var cancellationTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
||||||
navigateContext.CancellationToken.Register(state =>
|
|
||||||
((TaskCompletionSource)state).SetResult(), cancellationTcs);
|
|
||||||
|
|
||||||
var task = OnNavigateAsync.InvokeAsync(navigateContext);
|
|
||||||
|
|
||||||
// If the user provided a Navigating render fragment, then show it.
|
|
||||||
if (Navigating != null && task.Status != TaskStatus.RanToCompletion)
|
|
||||||
{
|
{
|
||||||
_renderHandle.Render(Navigating);
|
if (Navigating != null)
|
||||||
|
{
|
||||||
|
_renderHandle.Render(Navigating);
|
||||||
|
}
|
||||||
|
await OnNavigateAsync(navigateContext);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException e)
|
||||||
|
{
|
||||||
|
if (e.CancellationToken != navigateContext.CancellationToken)
|
||||||
|
{
|
||||||
|
var rethrownException = new InvalidOperationException("OnNavigateAsync can only be cancelled via NavigateContext.CancellationToken.", e);
|
||||||
|
_renderHandle.Render(builder => ExceptionDispatchInfo.Capture(rethrownException).Throw());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_renderHandle.Render(builder => ExceptionDispatchInfo.Capture(e).Throw());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var completedTask = await Task.WhenAny(task, cancellationTcs.Task);
|
return false;
|
||||||
return task == completedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task RunOnNavigateWithRefreshAsync(string path, bool isNavigationIntercepted)
|
internal async Task RunOnNavigateWithRefreshAsync(string path, bool isNavigationIntercepted)
|
||||||
{
|
{
|
||||||
// We cache the Task representing the previously invoked RunOnNavigateWithRefreshAsync
|
// We cache the Task representing the previously invoked RunOnNavigateWithRefreshAsync
|
||||||
// that is stored
|
// 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 previousTask = _previousOnNavigateTask;
|
||||||
// Then we create a new one that represents our current invocation and store it
|
|
||||||
// globally for the next invocation. Note to the developer, if the WASM runtime
|
|
||||||
// support multi-threading then we'll need to implement the appropriate locks
|
|
||||||
// here to ensure that the cached previous task is overwritten incorrectly.
|
|
||||||
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
_previousOnNavigateTask = tcs.Task;
|
_previousOnNavigateTask = tcs.Task;
|
||||||
try
|
try
|
||||||
|
|
|
||||||
|
|
@ -2,103 +2,253 @@
|
||||||
// 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.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Components;
|
|
||||||
using Microsoft.AspNetCore.Components.Routing;
|
using Microsoft.AspNetCore.Components.Routing;
|
||||||
using Microsoft.AspNetCore.Components.Test.Helpers;
|
using Microsoft.AspNetCore.Components.Test.Helpers;
|
||||||
using Microsoft.Extensions.DependencyModel;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Components.Test.Routing
|
namespace Microsoft.AspNetCore.Components.Test.Routing
|
||||||
{
|
{
|
||||||
public class RouterTest
|
public class RouterTest
|
||||||
{
|
{
|
||||||
|
private readonly Router _router;
|
||||||
|
private readonly TestRenderer _renderer;
|
||||||
|
|
||||||
|
public RouterTest()
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
|
||||||
|
services.AddSingleton<NavigationManager, TestNavigationManager>();
|
||||||
|
services.AddSingleton<INavigationInterception, TestNavigationInterception>();
|
||||||
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
|
|
||||||
|
_renderer = new TestRenderer(serviceProvider);
|
||||||
|
_renderer.ShouldHandleExceptions = true;
|
||||||
|
_router = (Router)_renderer.InstantiateComponent<Router>();
|
||||||
|
_router.AppAssembly = Assembly.GetExecutingAssembly();
|
||||||
|
_router.Found = routeData => (builder) => builder.AddContent(0, "Rendering route...");
|
||||||
|
_renderer.AssignRootComponentId(_router);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CanRunOnNavigateAsync()
|
public async Task CanRunOnNavigateAsync()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var router = CreateMockRouter();
|
|
||||||
var called = false;
|
var called = false;
|
||||||
async Task OnNavigateAsync(NavigationContext args)
|
async Task OnNavigateAsync(NavigationContext args)
|
||||||
{
|
{
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
called = true;
|
called = true;
|
||||||
}
|
}
|
||||||
router.Object.OnNavigateAsync = new EventCallbackFactory().Create<NavigationContext>(router, OnNavigateAsync);
|
_router.OnNavigateAsync = OnNavigateAsync;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await router.Object.RunOnNavigateWithRefreshAsync("http://example.com/jan", false);
|
await _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(called);
|
Assert.True(called);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CanCancelPreviousOnNavigateAsync()
|
public async Task CanHandleSingleFailedOnNavigateAsync()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var called = false;
|
||||||
|
async Task OnNavigateAsync(NavigationContext args)
|
||||||
|
{
|
||||||
|
called = true;
|
||||||
|
await Task.CompletedTask;
|
||||||
|
throw new Exception("This is an uncaught exception.");
|
||||||
|
}
|
||||||
|
_router.OnNavigateAsync = OnNavigateAsync;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(called);
|
||||||
|
Assert.Single(_renderer.HandledExceptions);
|
||||||
|
var unhandledException = _renderer.HandledExceptions[0];
|
||||||
|
Assert.Equal("This is an uncaught exception.", unhandledException.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CanceledFailedOnNavigateAsyncDoesNothing()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var onNavigateInvoked = 0;
|
||||||
|
async Task OnNavigateAsync(NavigationContext args)
|
||||||
|
{
|
||||||
|
onNavigateInvoked += 1;
|
||||||
|
if (args.Path.EndsWith("jan"))
|
||||||
|
{
|
||||||
|
await Task.Delay(Timeout.Infinite, args.CancellationToken);
|
||||||
|
throw new Exception("This is an uncaught exception.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var refreshCalled = false;
|
||||||
|
_renderer.OnUpdateDisplay = (renderBatch) =>
|
||||||
|
{
|
||||||
|
if (!refreshCalled)
|
||||||
|
{
|
||||||
|
refreshCalled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Assert.True(false, "OnUpdateDisplay called more than once.");
|
||||||
|
};
|
||||||
|
_router.OnNavigateAsync = OnNavigateAsync;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var janTask = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false));
|
||||||
|
var febTask = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/feb", false));
|
||||||
|
|
||||||
|
await janTask;
|
||||||
|
await febTask;
|
||||||
|
|
||||||
|
// Assert that we render the second route component and don't throw an exception
|
||||||
|
Assert.Empty(_renderer.HandledExceptions);
|
||||||
|
Assert.Equal(2, onNavigateInvoked);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CanHandleSingleCancelledOnNavigateAsync()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
async Task OnNavigateAsync(NavigationContext args)
|
||||||
|
{
|
||||||
|
var tcs = new TaskCompletionSource<int>();
|
||||||
|
tcs.TrySetCanceled();
|
||||||
|
await tcs.Task;
|
||||||
|
}
|
||||||
|
_renderer.OnUpdateDisplay = (renderBatch) => Assert.True(false, "OnUpdateDisplay called more than once.");
|
||||||
|
_router.OnNavigateAsync = OnNavigateAsync;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Single(_renderer.HandledExceptions);
|
||||||
|
var unhandledException = _renderer.HandledExceptions[0];
|
||||||
|
Assert.Equal("OnNavigateAsync can only be cancelled via NavigateContext.CancellationToken.", unhandledException.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AlreadyCanceledOnNavigateAsyncDoesNothing()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var triggerCancel = new TaskCompletionSource();
|
||||||
|
async Task OnNavigateAsync(NavigationContext args)
|
||||||
|
{
|
||||||
|
if (args.Path.EndsWith("jan"))
|
||||||
|
{
|
||||||
|
var tcs = new TaskCompletionSource();
|
||||||
|
await triggerCancel.Task;
|
||||||
|
tcs.TrySetCanceled();
|
||||||
|
await tcs.Task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var refreshCalled = false;
|
||||||
|
_renderer.OnUpdateDisplay = (renderBatch) =>
|
||||||
|
{
|
||||||
|
if (!refreshCalled)
|
||||||
|
{
|
||||||
|
Assert.True(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Assert.True(false, "OnUpdateDisplay called more than once.");
|
||||||
|
};
|
||||||
|
_router.OnNavigateAsync = OnNavigateAsync;
|
||||||
|
|
||||||
|
// Act (start the operations then await them)
|
||||||
|
var jan = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false));
|
||||||
|
var feb = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/feb", false));
|
||||||
|
triggerCancel.TrySetResult();
|
||||||
|
|
||||||
|
await jan;
|
||||||
|
await feb;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CanCancelPreviousOnNavigateAsync()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var router = CreateMockRouter();
|
|
||||||
var cancelled = "";
|
var cancelled = "";
|
||||||
async Task OnNavigateAsync(NavigationContext args)
|
async Task OnNavigateAsync(NavigationContext args)
|
||||||
{
|
{
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
args.CancellationToken.Register(() => cancelled = args.Path);
|
args.CancellationToken.Register(() => cancelled = args.Path);
|
||||||
};
|
};
|
||||||
router.Object.OnNavigateAsync = new EventCallbackFactory().Create<NavigationContext>(router, OnNavigateAsync);
|
_router.OnNavigateAsync = OnNavigateAsync;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await router.Object.RunOnNavigateWithRefreshAsync("jan", false);
|
_ = _router.RunOnNavigateWithRefreshAsync("jan", false);
|
||||||
await router.Object.RunOnNavigateWithRefreshAsync("feb", false);
|
_ = _router.RunOnNavigateWithRefreshAsync("feb", false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var expected = "jan";
|
var expected = "jan";
|
||||||
Assert.Equal(cancelled, expected);
|
Assert.Equal(expected, cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RefreshesOnceOnCancelledOnNavigateAsync()
|
public async Task RefreshesOnceOnCancelledOnNavigateAsync()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var router = CreateMockRouter();
|
|
||||||
async Task OnNavigateAsync(NavigationContext args)
|
async Task OnNavigateAsync(NavigationContext args)
|
||||||
{
|
{
|
||||||
if (args.Path.EndsWith("jan"))
|
if (args.Path.EndsWith("jan"))
|
||||||
{
|
{
|
||||||
await Task.Delay(Timeout.Infinite);
|
await Task.Delay(Timeout.Infinite, args.CancellationToken);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
router.Object.OnNavigateAsync = new EventCallbackFactory().Create<NavigationContext>(router, OnNavigateAsync);
|
var refreshCalled = false;
|
||||||
|
_renderer.OnUpdateDisplay = (renderBatch) =>
|
||||||
|
{
|
||||||
|
if (!refreshCalled)
|
||||||
|
{
|
||||||
|
Assert.True(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Assert.True(false, "OnUpdateDisplay called more than once.");
|
||||||
|
};
|
||||||
|
_router.OnNavigateAsync = OnNavigateAsync;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var janTask = router.Object.RunOnNavigateWithRefreshAsync("jan", false);
|
var jan = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false));
|
||||||
var febTask = router.Object.RunOnNavigateWithRefreshAsync("feb", false);
|
var feb = _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/feb", false));
|
||||||
|
|
||||||
var janTaskException = await Record.ExceptionAsync(() => janTask);
|
await jan;
|
||||||
var febTaskException = await Record.ExceptionAsync(() => febTask);
|
await feb;
|
||||||
|
|
||||||
// Assert neither execution threw an exception
|
|
||||||
Assert.Null(janTaskException);
|
|
||||||
Assert.Null(febTaskException);
|
|
||||||
// Assert refresh should've only been called once for the second route
|
|
||||||
router.Verify(x => x.Refresh(false), Times.Once());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mock<Router> CreateMockRouter()
|
internal class TestNavigationManager : NavigationManager
|
||||||
{
|
{
|
||||||
var router = new Mock<Router>() { CallBase = true };
|
public TestNavigationManager() =>
|
||||||
router.Setup(x => x.Refresh(It.IsAny<bool>())).Verifiable();
|
Initialize("https://www.example.com/subdir/", "https://www.example.com/subdir/jan");
|
||||||
return router;
|
|
||||||
|
protected override void NavigateToCore(string uri, bool forceLoad) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("jan")]
|
internal sealed class TestNavigationInterception : INavigationInterception
|
||||||
private class JanComponent : ComponentBase { }
|
{
|
||||||
|
public static readonly TestNavigationInterception Instance = new TestNavigationInterception();
|
||||||
|
|
||||||
|
public Task EnableNavigationInterceptionAsync()
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Route("feb")]
|
[Route("feb")]
|
||||||
private class FebComponent : ComponentBase { }
|
public class FebComponent : ComponentBase { }
|
||||||
|
|
||||||
|
[Route("jan")]
|
||||||
|
public class JanComponent : ComponentBase { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,10 @@
|
||||||
"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\\Sdk\\test\\Microsoft.NET.Sdk.BlazorWebAssembly.Tests.csproj",
|
||||||
|
"src\\Components\\WebAssembly\\Sdk\\tools\\Microsoft.NET.Sdk.BlazorWebAssembly.Tools.csproj",
|
||||||
|
"src\\Components\\WebAssembly\\Sdk\\integrationtests\\Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests.csproj",
|
||||||
"src\\Components\\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\\Driver\\Wasm.Performance.Driver.csproj",
|
"src\\Components\\benchmarkapps\\Wasm.Performance\\Driver\\Wasm.Performance.Driver.csproj",
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,6 @@
|
||||||
<Project>
|
<Project>
|
||||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, Directory.Build.props))\Directory.Build.props" />
|
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, Directory.Build.props))\Directory.Build.props" />
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<!-- Workaround for https://github.com/dotnet/aspnetcore/issues/5486 which requires the bin and obj directory be in the project directory -->
|
|
||||||
<BaseIntermediateOutputPath />
|
|
||||||
<IntermediateOutputPath />
|
|
||||||
<BaseOutputPath />
|
|
||||||
<OutputPath />
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<EnableTypeScriptNuGetTarget>true</EnableTypeScriptNuGetTarget>
|
<EnableTypeScriptNuGetTarget>true</EnableTypeScriptNuGetTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<BlazorWebAssemblyJSPath>$(RepoRoot)src\Components\Web.JS\dist\$(Configuration)\blazor.webassembly.js</BlazorWebAssemblyJSPath>
|
<BlazorWebAssemblyJSPath>$(RepoRoot)src\Components\Web.JS\dist\$(Configuration)\blazor.webassembly.js</BlazorWebAssemblyJSPath>
|
||||||
<BlazorWebAssemblyJSMapPath>$(BlazorWebAssemblyJSPath).map</BlazorWebAssemblyJSMapPath>
|
<BlazorWebAssemblyJSMapPath>$(BlazorWebAssemblyJSPath).map</BlazorWebAssemblyJSMapPath>
|
||||||
|
|
||||||
<_BlazorDevServerPath>$(RepoRoot)src/Components/WebAssembly/DevServer/src/bin/$(Configuration)/$(DefaultNetCoreTargetFramework)/blazor-devserver.dll</_BlazorDevServerPath>
|
<_BlazorDevServerPath>$(ArtifactsDir)/bin/Microsoft.AspNetCore.Components.WebAssembly.DevServer/$(Configuration)/$(DefaultNetCoreTargetFramework)/blazor-devserver.dll</_BlazorDevServerPath>
|
||||||
<RunCommand>dotnet</RunCommand>
|
<RunCommand>dotnet</RunCommand>
|
||||||
<RunArguments>exec "$(_BlazorDevServerPath)" serve --applicationpath "$(TargetPath)" $(AdditionalRunArguments)</RunArguments>
|
<RunArguments>exec "$(_BlazorDevServerPath)" serve --applicationpath "$(TargetPath)" $(AdditionalRunArguments)</RunArguments>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!--
|
||||||
|
There's not much value in multi-targeting here, this doesn't run much .NET code, it tests MSBuild.
|
||||||
|
|
||||||
|
This is also a partial workaround for https://github.com/Microsoft/msbuild/issues/2661 - this project
|
||||||
|
has netcoreapp dependencies that need to be built first.
|
||||||
|
-->
|
||||||
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
|
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||||
|
|
||||||
|
<!-- Tests do not work on Helix yet -->
|
||||||
|
<BuildHelixPayload>false</BuildHelixPayload>
|
||||||
|
<TestAppsRoot>$(MSBuildProjectDirectory)\..\testassets\</TestAppsRoot>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(SharedSourceRoot)MSBuild.Testing\MSBuild.Testing.targets" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Build.Utilities.Core" />
|
||||||
|
<Reference Include="Microsoft.Extensions.DependencyModel" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="$(RepoRoot)src\Razor\test\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib.csproj" />
|
||||||
|
|
||||||
|
<ProjectReference Include="..\src\Microsoft.NET.Sdk.BlazorWebAssembly.csproj">
|
||||||
|
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||||
|
<SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
|
||||||
|
</ProjectReference>
|
||||||
|
|
||||||
|
<ProjectReference Include="$(RepoRoot)src\Razor\Microsoft.NET.Sdk.Razor\src\Microsoft.NET.Sdk.Razor.csproj">
|
||||||
|
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||||
|
<SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\src\BootJsonData.cs" LinkBase="Wasm" />
|
||||||
|
<Compile Include="..\src\AssetsManifestFile.cs" LinkBase="Wasm" />
|
||||||
|
<Compile Include="$(SharedSourceRoot)CommandLineUtils\**\*.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Target Name="GenerateTestData" BeforeTargets="GetAssemblyAttributes">
|
||||||
|
<Exec Condition="'$(OS)' == 'Windows_NT'" Command=""$(NuGetPackageRoot)vswhere\$(VSWhereVersion)\tools\vswhere.exe" -latest -prerelease -property installationPath -requires Microsoft.Component.MSBuild" ConsoleToMsBuild="true" StandardErrorImportance="high">
|
||||||
|
<Output TaskParameter="ConsoleOutput" PropertyName="_VSInstallDir" />
|
||||||
|
</Exec>
|
||||||
|
<Error Condition="'$(OS)' == 'Windows_NT' and '$(_VSInstallDir)'=='' and '$(Test)' == 'true'" Text="Visual Studio not found on Windows." />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<_DesktopMSBuildPath Condition="'$(OS)' == 'Windows_NT' and Exists('$(_VSInstallDir)\MSBuild\Current\Bin\msbuild.exe')">$(_VSInstallDir)\MSBuild\Current\Bin\msbuild.exe</_DesktopMSBuildPath>
|
||||||
|
<_DesktopMSBuildPath Condition="'$(OS)' == 'Windows_NT' and Exists('$(_VSInstallDir)\MSBuild\15.0\Bin\msbuild.exe')">$(_VSInstallDir)\MSBuild\15.0\Bin\msbuild.exe</_DesktopMSBuildPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Error Condition="'$(OS)' == 'Windows_NT' and '$(_DesktopMSBuildPath)'=='' and '$(Test)' == 'true'" Text="MSBuild.exe not found on Windows." />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>DesktopMSBuildPath</_Parameter1>
|
||||||
|
<_Parameter2>$(_DesktopMSBuildPath)</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="RestoreTestProjects" BeforeTargets="Restore;Build" Condition="'$(DotNetBuildFromSource)' != 'true'">
|
||||||
|
<MSBuild Projects="..\testassets\RestoreBlazorWasmTestProjects\RestoreBlazorWasmTestProjects.csproj" Targets="Restore" Properties="MicrosoftNetCompilersToolsetPackageVersion=$(MicrosoftNetCompilersToolsetPackageVersion);RepoRoot=$(RepoRoot)" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="EnsureLogFolder" AfterTargets="Build">
|
||||||
|
<MakeDir Directories="$([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'log', '$(_BuildConfig)'))" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -6,7 +6,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Microsoft.AspNetCore.Razor.Tasks;
|
using Microsoft.NET.Sdk.BlazorWebAssembly;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
{
|
{
|
||||||
|
|
@ -4,7 +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.Razor.Tasks;
|
using Microsoft.NET.Sdk.BlazorWebAssembly;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
|
|
@ -4,7 +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.Razor.Tasks;
|
using Microsoft.NET.Sdk.BlazorWebAssembly;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -4,7 +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.Razor.Tasks;
|
using Microsoft.NET.Sdk.BlazorWebAssembly;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
|
|
@ -5,7 +5,7 @@ using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Razor.Tasks;
|
using Microsoft.NET.Sdk.BlazorWebAssembly;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using static Microsoft.AspNetCore.Razor.Design.IntegrationTests.ServiceWorkerAssert;
|
using static Microsoft.AspNetCore.Razor.Design.IntegrationTests.ServiceWorkerAssert;
|
||||||
|
|
@ -608,6 +608,17 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
assetsManifestPath: "custom-service-worker-assets.js");
|
assetsManifestPath: "custom-service-worker-assets.js");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Publish_HostedApp_WithRidSpecifiedInCLI_Works()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
using var project = ProjectDirectory.Create("blazorhosted-rid", additionalProjects: new[] { "blazorwasm", "razorclasslibrary", });
|
||||||
|
project.RuntimeIdentifier = "linux-x64";
|
||||||
|
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", "/p:RuntimeIdentifier=linux-x64");
|
||||||
|
|
||||||
|
AssertRIDPublishOuput(project, result);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Publish_HostedApp_WithRid_Works()
|
public async Task Publish_HostedApp_WithRid_Works()
|
||||||
{
|
{
|
||||||
|
|
@ -616,6 +627,11 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
project.RuntimeIdentifier = "linux-x64";
|
project.RuntimeIdentifier = "linux-x64";
|
||||||
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
|
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
|
||||||
|
|
||||||
|
AssertRIDPublishOuput(project, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AssertRIDPublishOuput(ProjectDirectory project, MSBuildResult result)
|
||||||
|
{
|
||||||
Assert.BuildPassed(result);
|
Assert.BuildPassed(result);
|
||||||
|
|
||||||
var publishDirectory = project.PublishOutputDirectory;
|
var publishDirectory = project.PublishOutputDirectory;
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"methodDisplay": "method",
|
||||||
|
"shadowCopy": false,
|
||||||
|
"maxParallelThreads": -1
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly
|
||||||
|
{
|
||||||
|
#pragma warning disable IDE1006 // Naming Styles
|
||||||
|
public class AssetsManifestFile
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a version string.
|
||||||
|
/// </summary>
|
||||||
|
public string version { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the assets. Keys are URLs; values are base-64-formatted SHA256 content hashes.
|
||||||
|
/// </summary>
|
||||||
|
public AssetsManifestFileEntry[] assets { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AssetsManifestFileEntry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the asset URL. Normally this will be relative to the application's base href.
|
||||||
|
/// </summary>
|
||||||
|
public string url { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the file content hash. This should be the base-64-formatted SHA256 value.
|
||||||
|
/// </summary>
|
||||||
|
public string hash { get; set; }
|
||||||
|
}
|
||||||
|
#pragma warning restore IDE1006 // Naming Styles
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly
|
||||||
|
{
|
||||||
|
public class BlazorReadSatelliteAssemblyFile : Task
|
||||||
|
{
|
||||||
|
[Output]
|
||||||
|
public ITaskItem[] SatelliteAssembly { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public ITaskItem ReadFile { get; set; }
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
var document = XDocument.Load(ReadFile.ItemSpec);
|
||||||
|
SatelliteAssembly = document.Root
|
||||||
|
.Elements()
|
||||||
|
.Select(e =>
|
||||||
|
{
|
||||||
|
// <Assembly Name="..." Culture="..." DestinationSubDirectory="..." />
|
||||||
|
|
||||||
|
var taskItem = new TaskItem(e.Attribute("Name").Value);
|
||||||
|
taskItem.SetMetadata("Culture", e.Attribute("Culture").Value);
|
||||||
|
taskItem.SetMetadata("DestinationSubDirectory", e.Attribute("DestinationSubDirectory").Value);
|
||||||
|
|
||||||
|
return taskItem;
|
||||||
|
}).ToArray();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly
|
||||||
|
{
|
||||||
|
public class BlazorWriteSatelliteAssemblyFile : Task
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] SatelliteAssembly { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public ITaskItem WriteFile { get; set; }
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
using var fileStream = File.Create(WriteFile.ItemSpec);
|
||||||
|
WriteSatelliteAssemblyFile(fileStream);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WriteSatelliteAssemblyFile(Stream stream)
|
||||||
|
{
|
||||||
|
var root = new XElement("SatelliteAssembly");
|
||||||
|
|
||||||
|
foreach (var item in SatelliteAssembly)
|
||||||
|
{
|
||||||
|
// <Assembly Name="..." Culture="..." DestinationSubDirectory="..." />
|
||||||
|
|
||||||
|
root.Add(new XElement("Assembly",
|
||||||
|
new XAttribute("Name", item.ItemSpec),
|
||||||
|
new XAttribute("Culture", item.GetMetadata("Culture")),
|
||||||
|
new XAttribute("DestinationSubDirectory", item.GetMetadata("DestinationSubDirectory"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
var xmlWriterSettings = new XmlWriterSettings
|
||||||
|
{
|
||||||
|
Indent = true,
|
||||||
|
OmitXmlDeclaration = true
|
||||||
|
};
|
||||||
|
|
||||||
|
using var writer = XmlWriter.Create(stream, xmlWriterSettings);
|
||||||
|
var xDocument = new XDocument(root);
|
||||||
|
|
||||||
|
xDocument.Save(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary<string, string>;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly
|
||||||
|
{
|
||||||
|
#pragma warning disable IDE1006 // Naming Styles
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the structure of a Blazor boot JSON file
|
||||||
|
/// </summary>
|
||||||
|
public class BootJsonData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the assembly with the application entry point
|
||||||
|
/// </summary>
|
||||||
|
public string entryAssembly { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the set of resources needed to boot the application. This includes the transitive
|
||||||
|
/// closure of .NET assemblies (including the entrypoint assembly), the dotnet.wasm file,
|
||||||
|
/// and any PDBs to be loaded.
|
||||||
|
///
|
||||||
|
/// Within <see cref="ResourceHashesByNameDictionary"/>, dictionary keys are resource names,
|
||||||
|
/// and values are SHA-256 hashes formatted in prefixed base-64 style (e.g., 'sha256-abcdefg...')
|
||||||
|
/// as used for subresource integrity checking.
|
||||||
|
/// </summary>
|
||||||
|
public ResourcesData resources { get; set; } = new ResourcesData();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value that determines whether to enable caching of the <see cref="resources"/>
|
||||||
|
/// inside a CacheStorage instance within the browser.
|
||||||
|
/// </summary>
|
||||||
|
public bool cacheBootResources { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value that determines if this is a debug build.
|
||||||
|
/// </summary>
|
||||||
|
public bool debugBuild { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value that determines if the linker is enabled.
|
||||||
|
/// </summary>
|
||||||
|
public bool linkerEnabled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Config files for the application
|
||||||
|
/// </summary>
|
||||||
|
public List<string> config { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ResourcesData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// .NET Wasm runtime resources (dotnet.wasm, dotnet.js) etc.
|
||||||
|
/// </summary>
|
||||||
|
public ResourceHashesByNameDictionary runtime { get; set; } = new ResourceHashesByNameDictionary();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "assembly" (.dll) resources
|
||||||
|
/// </summary>
|
||||||
|
public ResourceHashesByNameDictionary assembly { get; set; } = new ResourceHashesByNameDictionary();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "debug" (.pdb) resources
|
||||||
|
/// </summary>
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public ResourceHashesByNameDictionary pdb { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// localization (.satellite resx) resources
|
||||||
|
/// </summary>
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public Dictionary<string, ResourceHashesByNameDictionary> satelliteResources { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Assembly (.dll) resources that are loaded lazily during runtime
|
||||||
|
/// </summary>
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public ResourceHashesByNameDictionary lazyAssembly { get; set; }
|
||||||
|
}
|
||||||
|
#pragma warning restore IDE1006 // Naming Styles
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
// 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.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly
|
||||||
|
{
|
||||||
|
public class BrotliCompress : ToolTask
|
||||||
|
{
|
||||||
|
private static readonly char[] InvalidPathChars = Path.GetInvalidFileNameChars();
|
||||||
|
private string _dotnetPath;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] FilesToCompress { get; set; }
|
||||||
|
|
||||||
|
[Output]
|
||||||
|
public ITaskItem[] CompressedFiles { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string OutputDirectory { get; set; }
|
||||||
|
|
||||||
|
public string CompressionLevel { get; set; }
|
||||||
|
|
||||||
|
public bool SkipIfOutputIsNewer { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string ToolAssembly { get; set; }
|
||||||
|
|
||||||
|
protected override string ToolName => Path.GetDirectoryName(DotNetPath);
|
||||||
|
|
||||||
|
private string DotNetPath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(_dotnetPath))
|
||||||
|
{
|
||||||
|
return _dotnetPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dotnetPath = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH");
|
||||||
|
if (string.IsNullOrEmpty(_dotnetPath))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("DOTNET_HOST_PATH is not set");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _dotnetPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string GenerateCommandLineCommands() => ToolAssembly;
|
||||||
|
|
||||||
|
protected override string GenerateResponseFileCommands()
|
||||||
|
{
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
|
|
||||||
|
builder.AppendLine("brotli");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(CompressionLevel))
|
||||||
|
{
|
||||||
|
builder.AppendLine("-c");
|
||||||
|
builder.AppendLine(CompressionLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressedFiles = new ITaskItem[FilesToCompress.Length];
|
||||||
|
|
||||||
|
for (var i = 0; i < FilesToCompress.Length; i++)
|
||||||
|
{
|
||||||
|
var input = FilesToCompress[i];
|
||||||
|
var inputFullPath = input.GetMetadata("FullPath");
|
||||||
|
var relativePath = input.GetMetadata("RelativePath");
|
||||||
|
var outputRelativePath = Path.Combine(OutputDirectory, CalculateTargetPath(inputFullPath, ".br"));
|
||||||
|
var outputFullPath = Path.GetFullPath(outputRelativePath);
|
||||||
|
|
||||||
|
var outputItem = new TaskItem(outputRelativePath);
|
||||||
|
outputItem.SetMetadata("RelativePath", relativePath + ".br");
|
||||||
|
CompressedFiles[i] = outputItem;
|
||||||
|
|
||||||
|
if (SkipIfOutputIsNewer && File.Exists(outputFullPath) && File.GetLastWriteTimeUtc(inputFullPath) < File.GetLastWriteTimeUtc(outputFullPath))
|
||||||
|
{
|
||||||
|
Log.LogMessage(MessageImportance.Low, $"Skipping compression for '{input.ItemSpec}' because '{outputRelativePath}' is newer than '{input.ItemSpec}'.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.AppendLine("-s");
|
||||||
|
builder.AppendLine(inputFullPath);
|
||||||
|
|
||||||
|
builder.AppendLine("-o");
|
||||||
|
builder.AppendLine(outputFullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string CalculateTargetPath(string relativePath, string extension)
|
||||||
|
{
|
||||||
|
// RelativePath can be long and if used as-is to write the output, might result in long path issues on Windows.
|
||||||
|
// Instead we'll calculate a fixed length path by hashing the input file name. This uses SHA1 similar to the Hash task in MSBuild
|
||||||
|
// since it has no crytographic significance.
|
||||||
|
using var hash = SHA1.Create();
|
||||||
|
var bytes = Encoding.UTF8.GetBytes(relativePath);
|
||||||
|
var hashString = Convert.ToBase64String(hash.ComputeHash(bytes));
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
|
for (var i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
var c = hashString[i];
|
||||||
|
builder.Append(InvalidPathChars.Contains(c) ? '+' : c);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(extension);
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string GenerateFullPathToTool() => DotNetPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly
|
||||||
|
{
|
||||||
|
// Based on https://github.com/mono/linker/blob/3b329b9481e300bcf4fb88a2eebf8cb5ef8b323b/src/ILLink.Tasks/CreateRootDescriptorFile.cs
|
||||||
|
public class CreateBlazorTrimmerRootDescriptorFile : Task
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] Assemblies { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public ITaskItem TrimmerFile { get; set; }
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
var rootDescriptor = CreateRootDescriptorContents();
|
||||||
|
if (File.Exists(TrimmerFile.ItemSpec))
|
||||||
|
{
|
||||||
|
var existing = File.ReadAllText(TrimmerFile.ItemSpec);
|
||||||
|
|
||||||
|
if (string.Equals(rootDescriptor, existing, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Log.LogMessage(MessageImportance.Low, "Skipping write to file {0} because contents would not change.", TrimmerFile.ItemSpec);
|
||||||
|
// Avoid writing if the file contents are identical. This is required for build incrementalism.
|
||||||
|
return !Log.HasLoggedErrors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllText(TrimmerFile.ItemSpec, rootDescriptor);
|
||||||
|
return !Log.HasLoggedErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string CreateRootDescriptorContents()
|
||||||
|
{
|
||||||
|
var roots = new XElement("linker");
|
||||||
|
foreach (var assembly in Assemblies.OrderBy(a => a.ItemSpec))
|
||||||
|
{
|
||||||
|
// NOTE: Descriptor files don't include the file extension
|
||||||
|
// in the assemblyName.
|
||||||
|
var assemblyName = assembly.GetMetadata("FileName");
|
||||||
|
var typePreserved = assembly.GetMetadata("Preserve");
|
||||||
|
var typeRequired = assembly.GetMetadata("Required");
|
||||||
|
|
||||||
|
var attributes = new List<XAttribute>
|
||||||
|
{
|
||||||
|
new XAttribute("fullname", "*"),
|
||||||
|
new XAttribute("required", typeRequired),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(typePreserved))
|
||||||
|
{
|
||||||
|
attributes.Add(new XAttribute("preserve", typePreserved));
|
||||||
|
}
|
||||||
|
|
||||||
|
roots.Add(new XElement("assembly",
|
||||||
|
new XAttribute("fullname", assemblyName),
|
||||||
|
new XElement("type", attributes)));
|
||||||
|
}
|
||||||
|
|
||||||
|
var xmlWriterSettings = new XmlWriterSettings
|
||||||
|
{
|
||||||
|
Indent = true,
|
||||||
|
OmitXmlDeclaration = true
|
||||||
|
};
|
||||||
|
|
||||||
|
return new XDocument(roots).Root.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly
|
||||||
|
{
|
||||||
|
public class GZipCompress : Task
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] FilesToCompress { get; set; }
|
||||||
|
|
||||||
|
[Output]
|
||||||
|
public ITaskItem[] CompressedFiles { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string OutputDirectory { get; set; }
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
CompressedFiles = new ITaskItem[FilesToCompress.Length];
|
||||||
|
|
||||||
|
Directory.CreateDirectory(OutputDirectory);
|
||||||
|
|
||||||
|
System.Threading.Tasks.Parallel.For(0, FilesToCompress.Length, i =>
|
||||||
|
{
|
||||||
|
var file = FilesToCompress[i];
|
||||||
|
var inputPath = file.ItemSpec;
|
||||||
|
var relativePath = file.GetMetadata("RelativePath");
|
||||||
|
var outputRelativePath = Path.Combine(
|
||||||
|
OutputDirectory,
|
||||||
|
BrotliCompress.CalculateTargetPath(relativePath, ".gz"));
|
||||||
|
|
||||||
|
var outputItem = new TaskItem(outputRelativePath);
|
||||||
|
outputItem.SetMetadata("RelativePath", relativePath + ".gz");
|
||||||
|
CompressedFiles[i] = outputItem;
|
||||||
|
|
||||||
|
if (File.Exists(outputRelativePath) && File.GetLastWriteTimeUtc(inputPath) < File.GetLastWriteTimeUtc(outputRelativePath))
|
||||||
|
{
|
||||||
|
// Incrementalism. If input source doesn't exist or it exists and is not newer than the expected output, do nothing.
|
||||||
|
Log.LogMessage(MessageImportance.Low, $"Skipping '{inputPath}' because '{outputRelativePath}' is newer than '{inputPath}'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var sourceStream = File.OpenRead(inputPath);
|
||||||
|
using var fileStream = File.Create(outputRelativePath);
|
||||||
|
using var stream = new GZipStream(fileStream, CompressionLevel.Optimal);
|
||||||
|
|
||||||
|
sourceStream.CopyTo(stream);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.LogErrorFromException(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return !Log.HasLoggedErrors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.Serialization.Json;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary<string, string>;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly
|
||||||
|
{
|
||||||
|
public class GenerateBlazorWebAssemblyBootJson : Task
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string AssemblyPath { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] Resources { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public bool DebugBuild { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public bool LinkerEnabled { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public bool CacheBootResources { get; set; }
|
||||||
|
|
||||||
|
public ITaskItem[] ConfigurationFiles { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string OutputPath { get; set; }
|
||||||
|
|
||||||
|
public ITaskItem[] LazyLoadedAssemblies { get; set; }
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
using var fileStream = File.Create(OutputPath);
|
||||||
|
var entryAssemblyName = AssemblyName.GetAssemblyName(AssemblyPath).Name;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
WriteBootJson(fileStream, entryAssemblyName);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.LogErrorFromException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !Log.HasLoggedErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for tests
|
||||||
|
public void WriteBootJson(Stream output, string entryAssemblyName)
|
||||||
|
{
|
||||||
|
var result = new BootJsonData
|
||||||
|
{
|
||||||
|
entryAssembly = entryAssemblyName,
|
||||||
|
cacheBootResources = CacheBootResources,
|
||||||
|
debugBuild = DebugBuild,
|
||||||
|
linkerEnabled = LinkerEnabled,
|
||||||
|
resources = new ResourcesData(),
|
||||||
|
config = new List<string>(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build a two-level dictionary of the form:
|
||||||
|
// - assembly:
|
||||||
|
// - UriPath (e.g., "System.Text.Json.dll")
|
||||||
|
// - ContentHash (e.g., "4548fa2e9cf52986")
|
||||||
|
// - runtime:
|
||||||
|
// - UriPath (e.g., "dotnet.js")
|
||||||
|
// - ContentHash (e.g., "3448f339acf512448")
|
||||||
|
if (Resources != null)
|
||||||
|
{
|
||||||
|
var resourceData = result.resources;
|
||||||
|
foreach (var resource in Resources)
|
||||||
|
{
|
||||||
|
ResourceHashesByNameDictionary resourceList;
|
||||||
|
|
||||||
|
var fileName = resource.GetMetadata("FileName");
|
||||||
|
var extension = resource.GetMetadata("Extension");
|
||||||
|
var resourceCulture = resource.GetMetadata("Culture");
|
||||||
|
var assetType = resource.GetMetadata("AssetType");
|
||||||
|
var resourceName = $"{fileName}{extension}";
|
||||||
|
|
||||||
|
if (IsLazyLoadedAssembly(fileName))
|
||||||
|
{
|
||||||
|
resourceData.lazyAssembly ??= new ResourceHashesByNameDictionary();
|
||||||
|
resourceList = resourceData.lazyAssembly;
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(resourceCulture))
|
||||||
|
{
|
||||||
|
resourceData.satelliteResources ??= new Dictionary<string, ResourceHashesByNameDictionary>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
resourceName = resourceCulture + "/" + resourceName;
|
||||||
|
|
||||||
|
if (!resourceData.satelliteResources.TryGetValue(resourceCulture, out resourceList))
|
||||||
|
{
|
||||||
|
resourceList = new ResourceHashesByNameDictionary();
|
||||||
|
resourceData.satelliteResources.Add(resourceCulture, resourceList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (string.Equals(extension, ".pdb", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
resourceData.pdb ??= new ResourceHashesByNameDictionary();
|
||||||
|
resourceList = resourceData.pdb;
|
||||||
|
}
|
||||||
|
else if (string.Equals(extension, ".dll", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
resourceList = resourceData.assembly;
|
||||||
|
}
|
||||||
|
else if (string.Equals(assetType, "native", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
resourceList = resourceData.runtime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This should include items such as XML doc files, which do not need to be recorded in the manifest.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resourceList.ContainsKey(resourceName))
|
||||||
|
{
|
||||||
|
resourceList.Add(resourceName, $"sha256-{resource.GetMetadata("FileHash")}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ConfigurationFiles != null)
|
||||||
|
{
|
||||||
|
foreach (var configFile in ConfigurationFiles)
|
||||||
|
{
|
||||||
|
result.config.Add(Path.GetFileName(configFile.ItemSpec));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var serializer = new DataContractJsonSerializer(typeof(BootJsonData), new DataContractJsonSerializerSettings
|
||||||
|
{
|
||||||
|
UseSimpleDictionaryFormat = true
|
||||||
|
});
|
||||||
|
|
||||||
|
using var writer = JsonReaderWriterFactory.CreateJsonWriter(output, Encoding.UTF8, ownsStream: false, indent: true);
|
||||||
|
serializer.WriteObject(writer, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsLazyLoadedAssembly(string fileName)
|
||||||
|
{
|
||||||
|
return LazyLoadedAssemblies != null && LazyLoadedAssemblies.Any(a => a.ItemSpec == fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization.Json;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly
|
||||||
|
{
|
||||||
|
public partial class GenerateServiceWorkerAssetsManifest : Task
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] Assets { get; set; }
|
||||||
|
|
||||||
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string OutputPath { get; set; }
|
||||||
|
|
||||||
|
[Output]
|
||||||
|
public string CalculatedVersion { get; set; }
|
||||||
|
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
using var fileStream = File.Create(OutputPath);
|
||||||
|
CalculatedVersion = GenerateAssetManifest(fileStream);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string GenerateAssetManifest(Stream stream)
|
||||||
|
{
|
||||||
|
var assets = new AssetsManifestFileEntry[Assets.Length];
|
||||||
|
System.Threading.Tasks.Parallel.For(0, assets.Length, i =>
|
||||||
|
{
|
||||||
|
var item = Assets[i];
|
||||||
|
var hash = item.GetMetadata("FileHash");
|
||||||
|
var url = item.GetMetadata("AssetUrl");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(hash))
|
||||||
|
{
|
||||||
|
// Some files that are part of the service worker manifest may not have their hashes previously
|
||||||
|
// calcualted. Calculate them at this time.
|
||||||
|
using var sha = SHA256.Create();
|
||||||
|
using var file = File.OpenRead(item.ItemSpec);
|
||||||
|
var bytes = sha.ComputeHash(file);
|
||||||
|
|
||||||
|
hash = Convert.ToBase64String(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
assets[i] = new AssetsManifestFileEntry
|
||||||
|
{
|
||||||
|
hash = "sha256-" + hash,
|
||||||
|
url = url,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
var version = Version;
|
||||||
|
if (string.IsNullOrEmpty(version))
|
||||||
|
{
|
||||||
|
// If a version isn't specified (which is likely the most common case), construct a Version by combining
|
||||||
|
// the file names + hashes of all the inputs.
|
||||||
|
|
||||||
|
var combinedHash = string.Join(
|
||||||
|
Environment.NewLine,
|
||||||
|
assets.OrderBy(f => f.url, StringComparer.Ordinal).Select(f => f.hash));
|
||||||
|
|
||||||
|
using var sha = SHA256.Create();
|
||||||
|
var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(combinedHash));
|
||||||
|
version = Convert.ToBase64String(bytes).Substring(0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = new AssetsManifestFile
|
||||||
|
{
|
||||||
|
version = version,
|
||||||
|
assets = assets,
|
||||||
|
};
|
||||||
|
|
||||||
|
using var streamWriter = new StreamWriter(stream, Encoding.UTF8, bufferSize: 50, leaveOpen: true);
|
||||||
|
streamWriter.Write("self.assetsManifest = ");
|
||||||
|
streamWriter.Flush();
|
||||||
|
|
||||||
|
using var jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, ownsStream: false, indent: true);
|
||||||
|
new DataContractJsonSerializer(typeof(AssetsManifestFile)).WriteObject(jsonWriter, data);
|
||||||
|
jsonWriter.Flush();
|
||||||
|
|
||||||
|
streamWriter.WriteLine(";");
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Description>MSBuild support for building Blazor WebAssembly apps.</Description>
|
||||||
|
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net46</TargetFrameworks>
|
||||||
|
|
||||||
|
<TargetName>Microsoft.NET.Sdk.BlazorWebAssembly.Tasks</TargetName>
|
||||||
|
<NuspecFile>$(MSBuildProjectName).nuspec</NuspecFile>
|
||||||
|
<Serviceable>true</Serviceable>
|
||||||
|
<SdkOutputPath>$(ArtifactsBinDir)Microsoft.NET.Sdk.BlazorWebAssembly\$(Configuration)\sdk-output\</SdkOutputPath>
|
||||||
|
|
||||||
|
<!-- Allow assemblies outside of lib in the package -->
|
||||||
|
<NoWarn>$(NoWarn);NU5100</NoWarn>
|
||||||
|
<!-- Need to build this project in source build -->
|
||||||
|
<ExcludeFromSourceBuild>false</ExcludeFromSourceBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Build.Framework" />
|
||||||
|
<Reference Include="Microsoft.Build.Utilities.Core" />
|
||||||
|
|
||||||
|
<ProjectReference
|
||||||
|
Include="..\tools\Microsoft.NET.Sdk.BlazorWebAssembly.Tools.csproj"
|
||||||
|
Targets="Publish"
|
||||||
|
ReferenceOutputAssembly="false"
|
||||||
|
IsImplicityDefined="false"
|
||||||
|
SkipGetTargetFrameworkProperties="true"
|
||||||
|
UndefineProperties="TargetFramework;TargetFrameworks;RuntimeIdentifier;PublishDir" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="_._" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Target Name="LayoutDependencies" BeforeTargets="Build"
|
||||||
|
Condition="'$(IsInnerBuild)' != 'true' AND '$(NoBuild)' != 'true'">
|
||||||
|
<!-- Layout tasks, compiler, and extensions in the sdk-output folder. The entire folder structure gets packaged as-is into the SDK -->
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(ContinuousIntegrationBuild)' != 'true'">
|
||||||
|
<_ContinueOnError>true</_ContinueOnError>
|
||||||
|
<_Retries>1</_Retries>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(ContinuousIntegrationBuild)' == 'true'">
|
||||||
|
<_ContinueOnError>false</_ContinueOnError>
|
||||||
|
<_Retries>10</_Retries>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_WebAssemblyToolsOutput Include="$(ArtifactsBinDir)Microsoft.NET.Sdk.BlazorWebAssembly.Tools\$(Configuration)\$(DefaultNetCoreTargetFramework)\publish\Microsoft.*" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Error
|
||||||
|
Text="WebAssembly SDK tools outputs were not found in $(ArtifactsBinDir)Microsoft.NET.Sdk.BlazorWebAssembly.Tools\$(Configuration)\$(DefaultNetCoreTargetFramework)\publish"
|
||||||
|
Condition="'@(_WebAssemblyToolsOutput->Count())' == '0'" />
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(_WebAssemblyToolsOutput)"
|
||||||
|
DestinationFolder="$(SdkOutputPath)tools\$(DefaultNetCoreTargetFramework)\"
|
||||||
|
SkipUnchangedFiles="true"
|
||||||
|
Retries="$(_Retries)"
|
||||||
|
ContinueOnError="$(_ContinueOnError)" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectOutput Include="$(ArtifactsBinDir)Microsoft.NET.Sdk.BlazorWebAssembly\$(Configuration)\net46*\Microsoft.NET.Sdk.BlazorWebAssembly.*" />
|
||||||
|
<ProjectOutput Include="$(ArtifactsBinDir)Microsoft.NET.Sdk.BlazorWebAssembly\$(Configuration)\$(DefaultNetCoreTargetFramework)*\Microsoft.NET.Sdk.BlazorWebAssembly.*" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Copy SourceFiles="@(ProjectOutput)" DestinationFiles="$(SdkOutputPath)tasks\%(RecursiveDir)%(FileName)%(Extension)" SkipUnchangedFiles="true" Retries="$(_Retries)" ContinueOnError="$(_ContinueOnError)">
|
||||||
|
<Output TaskParameter="CopiedFiles" ItemName="FileWrites" />
|
||||||
|
</Copy>
|
||||||
|
|
||||||
|
<Message Text="Blazor WebAssembly SDK output -> $(SdkOutputPath)" Importance="High" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="PopulateNuspec" BeforeTargets="InitializeStandardNuspecProperties" DependsOnTargets="LayoutDependencies">
|
||||||
|
<PropertyGroup>
|
||||||
|
<PackageTags>$(PackageTags.Replace(';',' '))</PackageTags>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<NuspecProperty Include="outputPath=$(OutputPath)\sdk-output" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<!-- Workarounds to allow publishing to work when the SDK is referenced as a project. -->
|
||||||
|
<Target Name="GetTargetPath" />
|
||||||
|
<Target Name="GetCopyToPublishDirectoryItems" />
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
|
||||||
|
<metadata>
|
||||||
|
$CommonMetadataElements$
|
||||||
|
<dependencies>
|
||||||
|
<group targetFramework=".NET5.0" />
|
||||||
|
</dependencies>
|
||||||
|
</metadata>
|
||||||
|
|
||||||
|
<files>
|
||||||
|
$CommonFileElements$
|
||||||
|
<file src="Sdk\*" target="Sdk" />
|
||||||
|
<file src="build\**" target="build" />
|
||||||
|
<file src="targets\**" target="targets" />
|
||||||
|
<file src="_._" target="lib\net5.0\_._" />
|
||||||
|
|
||||||
|
<file src="$outputPath$\**" target="\" />
|
||||||
|
</files>
|
||||||
|
</package>
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<!--
|
||||||
|
***********************************************************************************************
|
||||||
|
Sdk.props
|
||||||
|
|
||||||
|
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
|
||||||
|
created a backup copy. Incorrect changes to this file will make it
|
||||||
|
impossible to load or build your projects from the command-line or the IDE.
|
||||||
|
|
||||||
|
Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
***********************************************************************************************
|
||||||
|
-->
|
||||||
|
<Project ToolsVersion="14.0" TreatAsLocalProperty="RuntimeIdentifier">
|
||||||
|
<PropertyGroup>
|
||||||
|
<UsingMicrosoftNETSdkBlazorWebAssembly>true</UsingMicrosoftNETSdkBlazorWebAssembly>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<_BlazorWebAssemblyPropsFile Condition="'$(_BlazorWebAssemblyPropsFile)' == ''">$(MSBuildThisFileDirectory)..\targets\Microsoft.NET.Sdk.BlazorWebAssembly.Current.props</_BlazorWebAssemblyPropsFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(_BlazorWebAssemblyPropsFile)" />
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!--
|
||||||
|
***********************************************************************************************
|
||||||
|
Sdk.targets
|
||||||
|
|
||||||
|
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
|
||||||
|
created a backup copy. Incorrect changes to this file will make it
|
||||||
|
impossible to load or build your projects from the command-line or the IDE.
|
||||||
|
|
||||||
|
Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
***********************************************************************************************
|
||||||
|
-->
|
||||||
|
<Project ToolsVersion="14.0">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<_BlazorWebAssemblyTargetsFile Condition="'$(_BlazorWebAssemblyTargetsFile)' == ''">$(MSBuildThisFileDirectory)..\targets\Microsoft.NET.Sdk.BlazorWebAssembly.Current.targets</_BlazorWebAssemblyTargetsFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(_BlazorWebAssemblyTargetsFile)" />
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!--
|
||||||
|
***********************************************************************************************
|
||||||
|
Microsoft.NET.Sdk.BlazorWebAssembly.props
|
||||||
|
|
||||||
|
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
|
||||||
|
created a backup copy. Incorrect changes to this file will make it
|
||||||
|
impossible to load or build your projects from the command-line or the IDE.
|
||||||
|
|
||||||
|
Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
***********************************************************************************************
|
||||||
|
-->
|
||||||
|
<Project ToolsVersion="14.0">
|
||||||
|
<PropertyGroup>
|
||||||
|
<_BlazorWebAssemblyPropsFile>$(MSBuildThisFileDirectory)..\..\targets\Microsoft.NET.Sdk.BlazorWebAssembly.Current.props</_BlazorWebAssemblyPropsFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!--
|
||||||
|
***********************************************************************************************
|
||||||
|
Microsoft.NET.Sdk.BlazorWebAssembly.props
|
||||||
|
|
||||||
|
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
|
||||||
|
created a backup copy. Incorrect changes to this file will make it
|
||||||
|
impossible to load or build your projects from the command-line or the IDE.
|
||||||
|
|
||||||
|
Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
***********************************************************************************************
|
||||||
|
-->
|
||||||
|
<Project ToolsVersion="14.0">
|
||||||
|
<PropertyGroup>
|
||||||
|
<_BlazorWebAssemblyTargetsFile>$(MSBuildThisFileDirectory)..\..\targets\Microsoft.NET.Sdk.BlazorWebAssembly.Current.targets</_BlazorWebAssemblyTargetsFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<system.webServer>
|
||||||
|
<staticContent>
|
||||||
|
<remove fileExtension=".dat" />
|
||||||
|
<remove fileExtension=".dll" />
|
||||||
|
<remove fileExtension=".json" />
|
||||||
|
<remove fileExtension=".wasm" />
|
||||||
|
<remove fileExtension=".woff" />
|
||||||
|
<remove fileExtension=".woff2" />
|
||||||
|
<mimeMap fileExtension=".dll" mimeType="application/octet-stream" />
|
||||||
|
<mimeMap fileExtension=".dat" mimeType="application/octet-stream" />
|
||||||
|
<mimeMap fileExtension=".json" mimeType="application/json" />
|
||||||
|
<mimeMap fileExtension=".wasm" mimeType="application/wasm" />
|
||||||
|
<mimeMap fileExtension=".woff" mimeType="application/font-woff" />
|
||||||
|
<mimeMap fileExtension=".woff2" mimeType="application/font-woff" />
|
||||||
|
</staticContent>
|
||||||
|
<httpCompression>
|
||||||
|
<dynamicTypes>
|
||||||
|
<add mimeType="application/octet-stream" enabled="true" />
|
||||||
|
<add mimeType="application/wasm" enabled="true" />
|
||||||
|
</dynamicTypes>
|
||||||
|
</httpCompression>
|
||||||
|
<rewrite>
|
||||||
|
<rules>
|
||||||
|
<rule name="Serve subdir">
|
||||||
|
<match url=".*" />
|
||||||
|
<action type="Rewrite" url="wwwroot\{R:0}" />
|
||||||
|
</rule>
|
||||||
|
<rule name="SPA fallback routing" stopProcessing="true">
|
||||||
|
<match url=".*" />
|
||||||
|
<conditions logicalGrouping="MatchAll">
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||||
|
</conditions>
|
||||||
|
<action type="Rewrite" url="wwwroot\" />
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
</rewrite>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<linker>
|
||||||
|
|
||||||
|
<!-- This file specifies which parts of the BCL or Blazor packages must not be stripped
|
||||||
|
by the IL linker even if they are not referenced by user code. The file format is
|
||||||
|
described at https://github.com/mono/linker/blob/master/src/linker/README.md#syntax-of-xml-descriptor -->
|
||||||
|
|
||||||
|
<assembly fullname="System">
|
||||||
|
<!-- Without this, [Required(typeof(bool), "true", "true", ErrorMessage = "...")] fails -->
|
||||||
|
<type fullname="System.ComponentModel.BooleanConverter" />
|
||||||
|
|
||||||
|
<!-- TypeConverters are only used through reflection. These are two built-in TypeConverters that are useful. -->
|
||||||
|
<type fullname="System.ComponentModel.GuidConverter" />
|
||||||
|
<type fullname="System.ComponentModel.TimeSpanConverter" />
|
||||||
|
</assembly>
|
||||||
|
</linker>
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<!--
|
||||||
|
***********************************************************************************************
|
||||||
|
Microsoft.NET.Sdk.BlazorWebAssembly.props
|
||||||
|
|
||||||
|
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
|
||||||
|
created a backup copy. Incorrect changes to this file will make it
|
||||||
|
impossible to load or build your projects from the command-line or the IDE.
|
||||||
|
|
||||||
|
Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
***********************************************************************************************
|
||||||
|
-->
|
||||||
|
<Project ToolsVersion="14.0" TreatAsLocalProperty="RuntimeIdentifier">
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- Blazor WASM projects are always browser-wasm -->
|
||||||
|
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
|
||||||
|
|
||||||
|
<!-- Avoid having the rid show up in output paths -->
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
|
|
||||||
|
<OutputType>exe</OutputType>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
|
||||||
|
<WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- Determines if this Sdk is responsible for importing Microsoft.NET.Sdk.Razor. Temporary workaround until we can create a SDK. -->
|
||||||
|
<_RazorSdkImportsMicrosoftNetSdkRazor Condition="'$(UsingMicrosoftNETSdkRazor)' != 'true'">true</_RazorSdkImportsMicrosoftNetSdkRazor>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Sdk="Microsoft.NET.Sdk.Razor" Project="Sdk.props" Condition="'$(_RazorSdkImportsMicrosoftNetSdkRazor)' == 'true'" />
|
||||||
|
<Import Sdk="Microsoft.NET.Sdk.Web.ProjectSystem" Project="Sdk.props" />
|
||||||
|
<Import Sdk="Microsoft.NET.Sdk.Publish" Project="Sdk.props" />
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,582 @@
|
||||||
|
<!--
|
||||||
|
***********************************************************************************************
|
||||||
|
Microsoft.NET.Sdk.BlazorWebAssembly.targets
|
||||||
|
|
||||||
|
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
|
||||||
|
created a backup copy. Incorrect changes to this file will make it
|
||||||
|
impossible to load or build your projects from the command-line or the IDE.
|
||||||
|
|
||||||
|
Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
***********************************************************************************************
|
||||||
|
-->
|
||||||
|
<Project ToolsVersion="14.0">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnableDefaultContentItems Condition=" '$(EnableDefaultContentItems)' == '' ">true</EnableDefaultContentItems>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Sdk="Microsoft.NET.Sdk.Razor" Project="Sdk.targets" Condition="'$(_RazorSdkImportsMicrosoftNetSdkRazor)' == 'true'" />
|
||||||
|
<Import Sdk="Microsoft.NET.Sdk.Web.ProjectSystem" Project="Sdk.targets" />
|
||||||
|
<Import Sdk="Microsoft.NET.Sdk.Publish" Project="Sdk.targets" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Targets supporting Razor MSBuild integration. Contain support for generating C# code using Razor
|
||||||
|
and including the generated code in the project lifecycle, including compiling, publishing and producing
|
||||||
|
nuget packages.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This is a hook to import a set of targets before the Blazor targets. By default this is unused.
|
||||||
|
-->
|
||||||
|
<Import Project="$(CustomBeforeBlazorWebAssemblySdkTargets)" Condition="'$(CustomBeforeBlazorWebAssemblySdkTargets)' != '' and Exists('$(CustomBeforeBlazorWebAssemblySdkTargets)')"/>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- Paths to tools, tasks, and extensions are calculated relative to the BlazorWebAssemblySdkDirectoryRoot. This can be modified to test a local build. -->
|
||||||
|
<BlazorWebAssemblySdkDirectoryRoot Condition="'$(BlazorWebAssemblySdkDirectoryRoot)'==''">$(MSBuildThisFileDirectory)..\..\</BlazorWebAssemblySdkDirectoryRoot>
|
||||||
|
<_BlazorWebAssemblySdkTasksTFM Condition=" '$(MSBuildRuntimeType)' == 'Core'">net5.0</_BlazorWebAssemblySdkTasksTFM>
|
||||||
|
<_BlazorWebAssemblySdkTasksTFM Condition=" '$(MSBuildRuntimeType)' != 'Core'">net46</_BlazorWebAssemblySdkTasksTFM>
|
||||||
|
<_BlazorWebAssemblySdkTasksAssembly>$(BlazorWebAssemblySdkDirectoryRoot)tasks\$(_BlazorWebAssemblySdkTasksTFM)\Microsoft.NET.Sdk.BlazorWebAssembly.Tasks.dll</_BlazorWebAssemblySdkTasksAssembly>
|
||||||
|
<_BlazorWebAssemblySdkToolAssembly>$(BlazorWebAssemblySdkDirectoryRoot)tools\net5.0\Microsoft.NET.Sdk.BlazorWebAssembly.Tools.dll</_BlazorWebAssemblySdkToolAssembly>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.GenerateBlazorWebAssemblyBootJson" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />
|
||||||
|
<UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.BlazorWriteSatelliteAssemblyFile" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />
|
||||||
|
<UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.BlazorReadSatelliteAssemblyFile" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />
|
||||||
|
<UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.BrotliCompress" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />
|
||||||
|
<UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.GzipCompress" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />
|
||||||
|
<UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.CreateBlazorTrimmerRootDescriptorFile" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
|
||||||
|
<!-- Trimmer defaults -->
|
||||||
|
<PublishTrimmed Condition="'$(PublishTrimmed)' == ''">true</PublishTrimmed>
|
||||||
|
<TrimMode Condition="'$(TrimMode)' == ''">link</TrimMode>
|
||||||
|
|
||||||
|
<StaticWebAssetBasePath Condition="'$(StaticWebAssetBasePath)' == ''">/</StaticWebAssetBasePath>
|
||||||
|
<BlazorCacheBootResources Condition="'$(BlazorCacheBootResources)' == ''">true</BlazorCacheBootResources>
|
||||||
|
|
||||||
|
<!-- Turn off parts of the build that do not apply to WASM projects -->
|
||||||
|
<GenerateDependencyFile>false</GenerateDependencyFile>
|
||||||
|
<GenerateRuntimeConfigurationFiles>false</GenerateRuntimeConfigurationFiles>
|
||||||
|
<PreserveCompilationContext>false</PreserveCompilationContext>
|
||||||
|
<PreserveCompilationReferences>false</PreserveCompilationReferences>
|
||||||
|
<IsWebConfigTransformDisabled>true</IsWebConfigTransformDisabled>
|
||||||
|
|
||||||
|
<!-- Internal properties -->
|
||||||
|
<_BlazorOutputPath>wwwroot\_framework\</_BlazorOutputPath>
|
||||||
|
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="Microsoft.NET.Sdk.BlazorWebAssembly.ServiceWorkerAssetsManifest.targets" />
|
||||||
|
|
||||||
|
<Target Name="_ScrambleDotnetJsFileName" AfterTargets="ResolveRuntimePackAssets">
|
||||||
|
<!--
|
||||||
|
We want the dotnet.js file output to have a version to better work with caching. We'll append the runtime version to the file name as soon as file has been discovered.
|
||||||
|
-->
|
||||||
|
<PropertyGroup>
|
||||||
|
<_DotNetJsVersion>$(BundledNETCoreAppPackageVersion)</_DotNetJsVersion>
|
||||||
|
<_DotNetJsVersion Condition="'$(RuntimeFrameworkVersion)' != ''">$(RuntimeFrameworkVersion)</_DotNetJsVersion>
|
||||||
|
<_BlazorDotnetJsFileName>dotnet.$(_DotNetJsVersion).js</_BlazorDotnetJsFileName>
|
||||||
|
<_BlazorDotNetJsFilePath>$(IntermediateOutputPath)$(_BlazorDotnetJsFileName)</_BlazorDotNetJsFilePath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_DotNetJsItem Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.DestinationSubPath)' == 'dotnet.js' AND '%(ReferenceCopyLocalPaths.AssetType)' == 'native'" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(_DotNetJsItem)"
|
||||||
|
DestinationFiles="$(_BlazorDotNetJsFilePath)"
|
||||||
|
SkipUnchangedFiles="true"
|
||||||
|
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)" />
|
||||||
|
|
||||||
|
<ItemGroup Condition="'@(_DotNetJsItem->Count())' != '0'">
|
||||||
|
<ReferenceCopyLocalPaths
|
||||||
|
Include="$(_BlazorDotNetJsFilePath)"
|
||||||
|
AssetType="native"
|
||||||
|
CopyLocal="true"
|
||||||
|
DestinationSubPath="$(_BlazorDotnetJsFileName)" />
|
||||||
|
|
||||||
|
<ReferenceCopyLocalPaths Remove="@(_DotNetJsItem)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_ResolveBlazorWasmOutputs" DependsOnTargets="ResolveReferences;PrepareResourceNames;ComputeIntermediateSatelliteAssemblies">
|
||||||
|
<!--
|
||||||
|
Calculates the outputs and the paths for Blazor WASM. This target is invoked frequently and should perform minimal work.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<_BlazorSatelliteAssemblyCacheFile>$(IntermediateOutputPath)blazor.satelliteasm.props</_BlazorSatelliteAssemblyCacheFile>
|
||||||
|
<!-- Workaround for https://github.com/dotnet/sdk/issues/12114-->
|
||||||
|
<PublishDir Condition="'$(AppendRuntimeIdentifierToOutputPath)' != 'true' AND '$(PublishDir)' == '$(OutputPath)$(RuntimeIdentifier)\$(PublishDirName)\'">$(OutputPath)$(PublishDirName)\</PublishDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_BlazorJSFile Include="$(BlazorWebAssemblyJSPath)" />
|
||||||
|
<_BlazorJSFile Include="$(BlazorWebAssemblyJSMapPath)" Condition="Exists('$(BlazorWebAssemblyJSMapPath)')" />
|
||||||
|
|
||||||
|
<_BlazorConfigFile Include="wwwroot\appsettings*.json" />
|
||||||
|
|
||||||
|
<!-- Clear out temporary build artifacts that the runtime packages -->
|
||||||
|
<ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.a'" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
ReferenceCopyLocalPaths includes satellite assemblies from referenced projects but are inexpicably missing
|
||||||
|
any metadata that might allow them to be differentiated. We'll explicitly add those
|
||||||
|
to _BlazorOutputWithTargetPath so that satellite assemblies from packages, the current project and referenced project
|
||||||
|
are all treated the same.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<_BlazorCopyLocalPath
|
||||||
|
Include="@(ReferenceCopyLocalPaths)"
|
||||||
|
Exclude="@(ReferenceSatellitePaths)"/>
|
||||||
|
|
||||||
|
<_BlazorCopyLocalPath Include="@(IntermediateSatelliteAssembliesWithTargetPath)">
|
||||||
|
<DestinationSubDirectory>%(IntermediateSatelliteAssembliesWithTargetPath.Culture)\</DestinationSubDirectory>
|
||||||
|
</_BlazorCopyLocalPath>
|
||||||
|
|
||||||
|
<_BlazorOutputWithTargetPath Include="
|
||||||
|
@(_BlazorCopyLocalPath);
|
||||||
|
@(IntermediateAssembly);
|
||||||
|
@(_DebugSymbolsIntermediatePath);
|
||||||
|
@(_BlazorJSFile)" />
|
||||||
|
|
||||||
|
<_BlazorOutputWithTargetPath Include="@(ReferenceSatellitePaths)">
|
||||||
|
<Culture>$([System.String]::Copy('%(ReferenceSatellitePaths.DestinationSubDirectory)').Trim('\').Trim('/'))</Culture>
|
||||||
|
</_BlazorOutputWithTargetPath>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
BuildingProject=false is typically set for referenced projects when building inside VisualStudio.
|
||||||
|
|
||||||
|
When building with BuildingProject=false, satellite assemblies do not get resolved (the ones for the current project and the one for
|
||||||
|
referenced project). Satellite assemblies from packages get resolved.
|
||||||
|
To workaround this, we'll cache metadata during a regular build, and rehydrate from it when BuildingProject=false.
|
||||||
|
-->
|
||||||
|
<BlazorReadSatelliteAssemblyFile
|
||||||
|
ReadFile="$(_BlazorSatelliteAssemblyCacheFile)"
|
||||||
|
Condition="'$(BuildingProject)' != 'true' AND EXISTS('$(_BlazorSatelliteAssemblyCacheFile)')">
|
||||||
|
<Output TaskParameter="SatelliteAssembly" ItemName="_BlazorReadSatelliteAssembly" />
|
||||||
|
</BlazorReadSatelliteAssemblyFile>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- We've imported a previously Cacheed file. Let's turn in to a _BlazorOutputWithTargetPath -->
|
||||||
|
<_BlazorOutputWithTargetPath
|
||||||
|
Include="@(_BlazorReadSatelliteAssembly)"
|
||||||
|
Exclude="@(_BlazorOutputWithTargetPath)"
|
||||||
|
Condition="'@(_BlazorReadSatelliteAssembly->Count())' != '0'" />
|
||||||
|
|
||||||
|
<!-- Calculate the target path -->
|
||||||
|
<_BlazorOutputWithTargetPath
|
||||||
|
TargetPath="$(_BlazorOutputPath)%(_BlazorOutputWithTargetPath.DestinationSubDirectory)%(FileName)%(Extension)"
|
||||||
|
Condition="'%(__BlazorOutputWithTargetPath.TargetPath)' == ''" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_ProcessBlazorWasmOutputs" DependsOnTargets="_ResolveBlazorWasmOutputs">
|
||||||
|
<PropertyGroup>
|
||||||
|
<_BlazorBuildGZipCompressDirectory>$(IntermediateOutputPath)build-gz\</_BlazorBuildGZipCompressDirectory>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Compress referenced binaries using GZip during build. This skips files such as the project's assemblies
|
||||||
|
that change from build to build. Runtime assets contribute to the bulk of the download size. Compressing it
|
||||||
|
has the most benefit while avoiding any ongoing costs to the dev inner loop.
|
||||||
|
-->
|
||||||
|
<ItemGroup>
|
||||||
|
<_GzipFileToCompressForBuild
|
||||||
|
Include="@(ReferenceCopyLocalPaths)"
|
||||||
|
RelativePath="$(_BlazorOutputPath)%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(FileName)%(Extension)"
|
||||||
|
Condition="'%(Extension)' == '.dll' or '%(ReferenceCopyLocalPaths.AssetType)' == 'native'" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<GZipCompress
|
||||||
|
FilesToCompress="@(_GzipFileToCompressForBuild)"
|
||||||
|
OutputDirectory="$(_BlazorBuildGZipCompressDirectory)">
|
||||||
|
|
||||||
|
<Output TaskParameter="CompressedFiles" ItemName="_BlazorBuildGZipCompressedFile" />
|
||||||
|
<Output TaskParameter="CompressedFiles" ItemName="FileWrites" />
|
||||||
|
</GZipCompress>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_BlazorWriteSatelliteAssembly Include="@(_BlazorOutputWithTargetPath->HasMetadata('Culture'))" />
|
||||||
|
|
||||||
|
<!-- Retarget ReferenceCopyLocalPaths to copy to the wwwroot directory -->
|
||||||
|
<ReferenceCopyLocalPaths DestinationSubDirectory="$(_BlazorOutputPath)%(ReferenceCopyLocalPaths.DestinationSubDirectory)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- A missing blazor.webassembly.js is our packaging error. Produce an error so it's discovered early. -->
|
||||||
|
<Error
|
||||||
|
Text="Unable to find BlazorWebAssembly JS files. This usually indicates a packaging error."
|
||||||
|
Code="RAZORSDK1007"
|
||||||
|
Condition="'@(_BlazorJSFile->Count())' == '0'" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
When building with BuildingProject=false, satellite assemblies do not get resolved (the ones for the current project and the one for
|
||||||
|
referenced project). BuildingProject=false is typically set for referenced projects when building inside VisualStudio.
|
||||||
|
To workaround this, we'll cache metadata during a regular build, and rehydrate from it when BuildingProject=false.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<BlazorWriteSatelliteAssemblyFile
|
||||||
|
SatelliteAssembly="@(_BlazorWriteSatelliteAssembly)"
|
||||||
|
WriteFile="$(_BlazorSatelliteAssemblyCacheFile)"
|
||||||
|
Condition="'$(BuildingProject)' == 'true' AND '@(_BlazorWriteSatelliteAssembly->Count())' != '0'" />
|
||||||
|
|
||||||
|
<Delete
|
||||||
|
Files="$(_BlazorSatelliteAssemblyCacheFile)"
|
||||||
|
Condition="'$(BuildingProject)' == 'true' AND '@(_BlazorWriteSatelliteAssembly->Count())' == '0' and EXISTS('$(_BlazorSatelliteAssemblyCacheFile)')" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<FileWrites Include="$(_BlazorSatelliteAssemblyCacheFile)" Condition="Exists('$(_BlazorSatelliteAssemblyCacheFile)')" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<GetFileHash Files="@(_BlazorOutputWithTargetPath)" Algorithm="SHA256" HashEncoding="base64">
|
||||||
|
<Output TaskParameter="Items" ItemName="_BlazorOutputWithHash" />
|
||||||
|
</GetFileHash>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<PrepareForRunDependsOn>
|
||||||
|
_BlazorWasmPrepareForRun;
|
||||||
|
$(PrepareForRunDependsOn)
|
||||||
|
</PrepareForRunDependsOn>
|
||||||
|
|
||||||
|
<GetCurrentProjectStaticWebAssetsDependsOn>
|
||||||
|
$(GetCurrentProjectStaticWebAssetsDependsOn);
|
||||||
|
_BlazorWasmPrepareForRun;
|
||||||
|
</GetCurrentProjectStaticWebAssetsDependsOn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Target Name="_BlazorWasmPrepareForRun" DependsOnTargets="_ProcessBlazorWasmOutputs" BeforeTargets="_RazorPrepareForRun" AfterTargets="GetCurrentProjectStaticWebAssets">
|
||||||
|
<PropertyGroup>
|
||||||
|
<_BlazorBuildBootJsonPath>$(IntermediateOutputPath)blazor.boot.json</_BlazorBuildBootJsonPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<GenerateBlazorWebAssemblyBootJson
|
||||||
|
AssemblyPath="@(IntermediateAssembly)"
|
||||||
|
Resources="@(_BlazorOutputWithHash)"
|
||||||
|
DebugBuild="true"
|
||||||
|
LinkerEnabled="false"
|
||||||
|
CacheBootResources="$(BlazorCacheBootResources)"
|
||||||
|
OutputPath="$(_BlazorBuildBootJsonPath)"
|
||||||
|
ConfigurationFiles="@(_BlazorConfigFile)"
|
||||||
|
LazyLoadedAssemblies="@(BlazorWebAssemblyLazyLoad)" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<FileWrites Include="$(OutDir)$(_BlazorOutputPath)blazor.boot.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_BlazorWebAssemblyStaticWebAsset Include="$(_BlazorBuildBootJsonPath)">
|
||||||
|
<SourceId>$(PackageId)</SourceId>
|
||||||
|
<SourceType></SourceType>
|
||||||
|
<ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
|
||||||
|
<BasePath>$(StaticWebAssetBasePath)</BasePath>
|
||||||
|
<RelativePath>_framework/blazor.boot.json</RelativePath>
|
||||||
|
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||||
|
</_BlazorWebAssemblyStaticWebAsset>
|
||||||
|
|
||||||
|
<_BlazorWebAssemblyStaticWebAsset Include="@(_BlazorOutputWithHash)">
|
||||||
|
<SourceId>$(PackageId)</SourceId>
|
||||||
|
<SourceType></SourceType>
|
||||||
|
<ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
|
||||||
|
<BasePath>$(StaticWebAssetBasePath)</BasePath>
|
||||||
|
<RelativePath>$([System.String]::Copy('%(_BlazorOutputWithHash.TargetPath)').Replace('\','/').Substring(8))</RelativePath>
|
||||||
|
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||||
|
</_BlazorWebAssemblyStaticWebAsset>
|
||||||
|
|
||||||
|
<_BlazorWebAssemblyStaticWebAsset Include="@(_BlazorBuildGZipCompressedFile)">
|
||||||
|
<SourceId>$(PackageId)</SourceId>
|
||||||
|
<SourceType></SourceType>
|
||||||
|
<ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
|
||||||
|
<BasePath>$(StaticWebAssetBasePath)</BasePath>
|
||||||
|
<RelativePath>$([System.String]::Copy('%(_BlazorBuildGZipCompressedFile.RelativePath)').Replace('\','/').Substring(8))</RelativePath>
|
||||||
|
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||||
|
</_BlazorWebAssemblyStaticWebAsset>
|
||||||
|
|
||||||
|
<StaticWebAsset Include="@(_BlazorWebAssemblyStaticWebAsset)" />
|
||||||
|
<_ExternalStaticWebAsset Include="@(_BlazorWebAssemblyStaticWebAsset)" SourceType="Generated" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<!-- Mimics the behavior of CopyFilesToOutputDirectory. We simply copy relevant build outputs to the wwwroot directory -->
|
||||||
|
<Target Name="_BlazorCopyFilesToOutputDirectory" AfterTargets="CopyFilesToOutputDirectory">
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(IntermediateAssembly)"
|
||||||
|
DestinationFolder="$(OutDir)$(_BlazorOutputPath)"
|
||||||
|
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
|
||||||
|
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
|
||||||
|
Retries="$(CopyRetryCount)"
|
||||||
|
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
|
||||||
|
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)"
|
||||||
|
Condition="'$(CopyBuildOutputToOutputDirectory)' == 'true' and '$(SkipCopyBuildProduct)' != 'true'">
|
||||||
|
|
||||||
|
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
|
||||||
|
</Copy>
|
||||||
|
|
||||||
|
<Message Importance="High" Text="$(MSBuildProjectName) (Blazor output) -> $(TargetDir)wwwroot" Condition="'$(CopyBuildOutputToOutputDirectory)' == 'true' and '$(SkipCopyBuildProduct)'!='true'" />
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(_DebugSymbolsIntermediatePath)"
|
||||||
|
DestinationFolder="$(OutDir)$(_BlazorOutputPath)"
|
||||||
|
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
|
||||||
|
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
|
||||||
|
Retries="$(CopyRetryCount)"
|
||||||
|
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
|
||||||
|
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)"
|
||||||
|
Condition="'$(_DebugSymbolsProduced)'=='true' and '$(SkipCopyingSymbolsToOutputDirectory)' != 'true' and '$(CopyOutputSymbolsToOutputDirectory)'=='true'">
|
||||||
|
|
||||||
|
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
|
||||||
|
</Copy>
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(IntermediateSatelliteAssembliesWithTargetPath)"
|
||||||
|
DestinationFiles="@(IntermediateSatelliteAssembliesWithTargetPath->'$(OutDir)$(_BlazorOutputPath)%(Culture)\$(TargetName).resources.dll')"
|
||||||
|
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
|
||||||
|
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
|
||||||
|
Retries="$(CopyRetryCount)"
|
||||||
|
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
|
||||||
|
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)"
|
||||||
|
Condition="'@(IntermediateSatelliteAssembliesWithTargetPath)' != ''" >
|
||||||
|
|
||||||
|
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
|
||||||
|
</Copy>
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(_BlazorJSFile);$(_BlazorBuildBootJsonPath)"
|
||||||
|
DestinationFolder="$(OutDir)$(_BlazorOutputPath)"
|
||||||
|
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
|
||||||
|
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
|
||||||
|
Retries="$(CopyRetryCount)"
|
||||||
|
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
|
||||||
|
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)">
|
||||||
|
|
||||||
|
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
|
||||||
|
</Copy>
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(_BlazorBuildGZipCompressedFile)"
|
||||||
|
DestinationFiles="@(_BlazorBuildGZipCompressedFile->'$(OutDir)%(RelativePath)')"
|
||||||
|
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
|
||||||
|
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
|
||||||
|
Retries="$(CopyRetryCount)"
|
||||||
|
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
|
||||||
|
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)">
|
||||||
|
|
||||||
|
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
|
||||||
|
</Copy>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_BlazorWasmPrepareForLink" BeforeTargets="PrepareForILLink">
|
||||||
|
<PropertyGroup>
|
||||||
|
<_BlazorTypeGranularTrimmerDescriptorFile>$(IntermediateOutputPath)typegranularity.trimmerdescriptor.xml</_BlazorTypeGranularTrimmerDescriptorFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_BlazorTypeGranularAssembly
|
||||||
|
Include="@(ManagedAssemblyToLink)"
|
||||||
|
Condition="'%(Extension)' == '.dll' AND ($([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.')) or $([System.String]::Copy('%(Filename)').StartsWith('Microsoft.Extensions.')))">
|
||||||
|
<Required>false</Required>
|
||||||
|
<Preserve>all</Preserve>
|
||||||
|
</_BlazorTypeGranularAssembly>
|
||||||
|
|
||||||
|
<ManagedAssemblyToLink
|
||||||
|
IsTrimmable="true"
|
||||||
|
Condition="'%(Extension)' == '.dll' AND ($([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.')) or $([System.String]::Copy('%(Filename)').StartsWith('Microsoft.Extensions.')))" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<CreateBlazorTrimmerRootDescriptorFile
|
||||||
|
Assemblies="@(_BlazorTypeGranularAssembly)"
|
||||||
|
TrimmerFile="$(_BlazorTypeGranularTrimmerDescriptorFile)" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<TrimmerRootDescriptor Include="$(_BlazorTypeGranularTrimmerDescriptorFile)" />
|
||||||
|
<TrimmerRootDescriptor Include="$(MSBuildThisFileDirectory)LinkerWorkaround.xml" />
|
||||||
|
|
||||||
|
<FileWrites Include="$(_BlazorTypeGranularTrimmerDescriptorFile)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_ProcessPublishFilesForBlazor" DependsOnTargets="_ResolveBlazorWasmOutputs" AfterTargets="ILLink">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
ResolvedFileToPublish.Culture is missing for satellite assemblies from project references.
|
||||||
|
Since we need the culture to correctly generate blazor.boot.json, we cross-reference the culture we calculate as part of _ResolveBlazorWasmOutputs
|
||||||
|
-->
|
||||||
|
<JoinItems Left="@(ResolvedFileToPublish)"
|
||||||
|
Right="@(_BlazorOutputWithTargetPath->HasMetadata('Culture'))"
|
||||||
|
LeftMetadata="*"
|
||||||
|
RightMetadata="Culture"
|
||||||
|
ItemSpecToUse="Left">
|
||||||
|
<Output TaskParameter="JoinResult" ItemName="_ResolvedSatelliteToPublish" />
|
||||||
|
</JoinItems>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ResolvedFileToPublish Remove="@(_ResolvedSatelliteToPublish)" />
|
||||||
|
<ResolvedFileToPublish Include="@(_ResolvedSatelliteToPublish)" />
|
||||||
|
|
||||||
|
<ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'%(Extension)' == '.a'" />
|
||||||
|
|
||||||
|
<!-- Remove dotnet.js from publish output -->
|
||||||
|
<ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.RelativePath)' == 'dotnet.js'" />
|
||||||
|
|
||||||
|
<!-- Retarget so that items are published to the wwwroot directory -->
|
||||||
|
<ResolvedFileToPublish
|
||||||
|
RelativePath="$(_BlazorOutputPath)%(ResolvedFileToPublish.RelativePath)"
|
||||||
|
Condition="'%(ResolvedFileToPublish.RelativePath)' != 'web.config' AND !$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))" />
|
||||||
|
|
||||||
|
<!-- Remove pdbs from the publish output -->
|
||||||
|
<ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'$(BlazorWebAssemblyEnableDebugging)' != 'true' AND '%(Extension)' == '.pdb'" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'@(ResolvedFileToPublish->AnyHaveMetadataValue('RelativePath', 'web.config'))' != 'true'">
|
||||||
|
<ResolvedFileToPublish
|
||||||
|
Include="$(MSBuildThisFileDirectory)BlazorWasm.web.config"
|
||||||
|
ExcludeFromSingleFile="true"
|
||||||
|
CopyToPublishDirectory="PreserveNewest"
|
||||||
|
RelativePath="web.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Generate the publish boot json -->
|
||||||
|
<ItemGroup>
|
||||||
|
<_BlazorPublishBootResource
|
||||||
|
Include="@(ResolvedFileToPublish)"
|
||||||
|
Condition="$([System.String]::Copy('%(RelativePath)').Replace('\','/').StartsWith('wwwroot/_framework')) AND '%(Extension)' != '.a'" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<GetFileHash Files="@(_BlazorPublishBootResource)" Algorithm="SHA256" HashEncoding="base64">
|
||||||
|
<Output TaskParameter="Items" ItemName="_BlazorPublishBootResourceWithHash" />
|
||||||
|
</GetFileHash>
|
||||||
|
|
||||||
|
<GenerateBlazorWebAssemblyBootJson
|
||||||
|
AssemblyPath="@(IntermediateAssembly)"
|
||||||
|
Resources="@(_BlazorPublishBootResourceWithHash)"
|
||||||
|
DebugBuild="false"
|
||||||
|
LinkerEnabled="$(PublishTrimmed)"
|
||||||
|
CacheBootResources="$(BlazorCacheBootResources)"
|
||||||
|
OutputPath="$(IntermediateOutputPath)blazor.publish.boot.json"
|
||||||
|
ConfigurationFiles="@(_BlazorConfigFile)"
|
||||||
|
LazyLoadedAssemblies="@(BlazorWebAssemblyLazyLoad)" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ResolvedFileToPublish
|
||||||
|
Include="$(IntermediateOutputPath)blazor.publish.boot.json"
|
||||||
|
RelativePath="$(_BlazorOutputPath)blazor.boot.json" />
|
||||||
|
|
||||||
|
<ResolvedFileToPublish
|
||||||
|
Include="@(_BlazorJSFile)"
|
||||||
|
RelativePath="$(_BlazorOutputPath)%(FileName)%(Extension)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_BlazorCompressPublishFiles" AfterTargets="_ProcessPublishFilesForBlazor" Condition="'$(BlazorEnableCompression)' != 'false'">
|
||||||
|
<PropertyGroup>
|
||||||
|
<_CompressedFileOutputPath>$(IntermediateOutputPath)compress\</_CompressedFileOutputPath>
|
||||||
|
<_BlazorWebAssemblyBrotliIncremental>true</_BlazorWebAssemblyBrotliIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_FileToCompress
|
||||||
|
Include="@(ResolvedFileToPublish)"
|
||||||
|
Condition="$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Message Text="Compressing Blazor WebAssembly publish artifacts. This may take a while..." Importance="High" />
|
||||||
|
|
||||||
|
<MakeDir Directories="$(_CompressedFileOutputPath)" Condition="!Exists('$(_CompressedFileOutputPath)')" />
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(DOTNET_HOST_PATH)' == ''">
|
||||||
|
<_DotNetHostDirectory>$(NetCoreRoot)</_DotNetHostDirectory>
|
||||||
|
<_DotNetHostFileName>dotnet</_DotNetHostFileName>
|
||||||
|
<_DotNetHostFileName Condition="'$(OS)' == 'Windows_NT'">dotnet.exe</_DotNetHostFileName>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<BrotliCompress
|
||||||
|
OutputDirectory="$(_CompressedFileOutputPath)"
|
||||||
|
FilesToCompress="@(_FileToCompress)"
|
||||||
|
CompressionLevel="$(_BlazorBrotliCompressionLevel)"
|
||||||
|
SkipIfOutputIsNewer="$(_BlazorWebAssemblyBrotliIncremental)"
|
||||||
|
ToolAssembly="$(_BlazorWebAssemblySdkToolAssembly)"
|
||||||
|
ToolExe="$(_DotNetHostFileName)"
|
||||||
|
ToolPath="$(_DotNetHostDirectory)">
|
||||||
|
|
||||||
|
<Output TaskParameter="CompressedFiles" ItemName="_BrotliCompressedFile" />
|
||||||
|
<Output TaskParameter="CompressedFiles" ItemName="FileWrites" />
|
||||||
|
</BrotliCompress>
|
||||||
|
|
||||||
|
<GZipCompress
|
||||||
|
OutputDirectory="$(_CompressedFileOutputPath)"
|
||||||
|
FilesToCompress="@(_FileToCompress)">
|
||||||
|
|
||||||
|
<Output TaskParameter="CompressedFiles" ItemName="_BlazorPublishGZipCompressedFile" />
|
||||||
|
<Output TaskParameter="CompressedFiles" ItemName="FileWrites" />
|
||||||
|
</GZipCompress>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ResolvedFileToPublish Include="@(_BrotliCompressedFile)" />
|
||||||
|
<ResolvedFileToPublish Include="@(_BlazorPublishGZipCompressedFile)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_SetupPublishSemaphore" BeforeTargets="PrepareForPublish">
|
||||||
|
<PropertyGroup>
|
||||||
|
<!--
|
||||||
|
Add marker that indicates Blazor WASM is doing a publish. This is used to identify when GetCopyToPublishDirectoryItems
|
||||||
|
is invoked as a result of a P2P reference.
|
||||||
|
-->
|
||||||
|
<_PublishingBlazorWasmProject>true</_PublishingBlazorWasmProject>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_GetBlazorWasmFilesForPublishInner"
|
||||||
|
DependsOnTargets="_ResolveBlazorWasmOutputs;ComputeFilesToPublish"
|
||||||
|
Returns="@(ResolvedFileToPublish)" />
|
||||||
|
|
||||||
|
<Target Name="_GetBlazorWasmFilesForPublish" BeforeTargets="GetCopyToPublishDirectoryItems">
|
||||||
|
<MSBuild
|
||||||
|
Projects="$(MSBuildProjectFullPath)"
|
||||||
|
Targets="_GetBlazorWasmFilesForPublishInner"
|
||||||
|
Properties="BuildProjectReferences=false;ResolveAssemblyReferencesFindRelatedSatellites=true;_PublishingBlazorWasmProject=true"
|
||||||
|
RemoveProperties="NoBuild;RuntimeIdentifier"
|
||||||
|
BuildInParallel="$(BuildInParallel)"
|
||||||
|
Condition="'$(_PublishingBlazorWasmProject)' != 'true'">
|
||||||
|
|
||||||
|
<Output TaskParameter="TargetOutputs" ItemName="_ResolvedFileToPublish" />
|
||||||
|
</MSBuild>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<AllPublishItemsFullPathWithTargetPath Include="@(_ResolvedFileToPublish->'%(FullPath)')">
|
||||||
|
<TargetPath>%(RelativePath)</TargetPath>
|
||||||
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
|
</AllPublishItemsFullPathWithTargetPath>
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_BlazorApplyLinkPreferencesToContent" BeforeTargets="AssignTargetPaths;ResolveCurrentProjectStaticWebAssetsInputs;ResolveStaticWebAssetsInputs" Returns="@(Content)">
|
||||||
|
<ItemGroup>
|
||||||
|
<Content
|
||||||
|
Condition="'%(Content.Link)' != '' AND '%(Content.CopyToPublishDirectory)' == '' AND $([System.String]::Copy('%(Content.Link)').Replace('\','/').StartsWith('wwwroot/'))"
|
||||||
|
CopyToPublishDirectory="PreserveNewest" />
|
||||||
|
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This is a hook to import a set of targets after the Blazor WebAssembly targets. By default this is unused.
|
||||||
|
-->
|
||||||
|
<Import Project="$(CustomAfterBlazorWebAssemblySdkTargets)" Condition="'$(CustomAfterBlazorWebAssemblySdkTargets)' != '' and Exists('$(CustomAfterBlazorWebAssemblySdkTargets)')"/>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
<!--
|
||||||
|
***********************************************************************************************
|
||||||
|
Microsoft.NET.Sdk.BlazorWebAssembly.ServiceWorkerAssetsManifest.targets
|
||||||
|
|
||||||
|
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
|
||||||
|
created a backup copy. Incorrect changes to this file will make it
|
||||||
|
impossible to load or build your projects from the command-line or the IDE.
|
||||||
|
|
||||||
|
Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
***********************************************************************************************
|
||||||
|
-->
|
||||||
|
|
||||||
|
<Project>
|
||||||
|
<UsingTask TaskName="Microsoft.NET.Sdk.BlazorWebAssembly.GenerateServiceWorkerAssetsManifest" AssemblyFile="$(_BlazorWebAssemblySdkTasksAssembly)" />
|
||||||
|
|
||||||
|
<Target Name="_ComputeServiceWorkerAssets" BeforeTargets="ResolveStaticWebAssetsInputs">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ServiceWorkerAssetsManifestIntermediateOutputPath Condition="'$([System.IO.Path]::IsPathRooted($(BaseIntermediateOutputPath)))' == 'true'">obj\$(Configuration)\$(TargetFramework)\$(ServiceWorkerAssetsManifest)</_ServiceWorkerAssetsManifestIntermediateOutputPath>
|
||||||
|
<_ServiceWorkerAssetsManifestIntermediateOutputPath Condition="'$([System.IO.Path]::IsPathRooted($(BaseIntermediateOutputPath)))' != 'true'">$(IntermediateOutputPath)$(ServiceWorkerAssetsManifest)</_ServiceWorkerAssetsManifestIntermediateOutputPath>
|
||||||
|
<_ServiceWorkerAssetsManifestFullPath>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)/$(_ServiceWorkerAssetsManifestIntermediateOutputPath)'))</_ServiceWorkerAssetsManifestFullPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_ManifestStaticWebAsset Include="$(_ServiceWorkerAssetsManifestFullPath)">
|
||||||
|
<SourceType></SourceType>
|
||||||
|
<SourceId>$(PackageId)</SourceId>
|
||||||
|
<ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
|
||||||
|
<BasePath>$(StaticWebAssetBasePath)</BasePath>
|
||||||
|
<RelativePath>$(ServiceWorkerAssetsManifest)</RelativePath>
|
||||||
|
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||||
|
</_ManifestStaticWebAsset>
|
||||||
|
|
||||||
|
<!-- Figure out where we're getting the content for each @(ServiceWorker) entry, depending on whether there's a PublishedContent value -->
|
||||||
|
<_ServiceWorkerIntermediateFile Include="@(ServiceWorker->'$(IntermediateOutputPath)serviceworkers\%(Identity)')">
|
||||||
|
<ContentSourcePath Condition="'%(_ServiceWorker.PublishedContent)' != ''">%(ServiceWorker.PublishedContent)</ContentSourcePath>
|
||||||
|
<ContentSourcePath Condition="'%(_ServiceWorker.PublishedContent)' == ''">%(ServiceWorker.Identity)</ContentSourcePath>
|
||||||
|
<OriginalPath>%(ServiceWorker.Identity)</OriginalPath>
|
||||||
|
<TargetOutputPath>%(ServiceWorker.Identity)</TargetOutputPath>
|
||||||
|
<TargetOutputPath Condition="$([System.String]::Copy('%(ServiceWorker.Identity)').Replace('\','/').StartsWith('wwwroot/'))">$([System.String]::Copy('%(ServiceWorker.Identity)').Substring(8))</TargetOutputPath>
|
||||||
|
</_ServiceWorkerIntermediateFile>
|
||||||
|
|
||||||
|
<_ServiceWorkerStaticWebAsset Include="%(_ServiceWorkerIntermediateFile.FullPath)">
|
||||||
|
<SourceType></SourceType>
|
||||||
|
<SourceId>$(PackageId)</SourceId>
|
||||||
|
<ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
|
||||||
|
<BasePath>$(StaticWebAssetBasePath)</BasePath>
|
||||||
|
<RelativePath>%(TargetOutputPath)</RelativePath>
|
||||||
|
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||||
|
</_ServiceWorkerStaticWebAsset>
|
||||||
|
|
||||||
|
<StaticWebAsset Include="
|
||||||
|
@(_ManifestStaticWebAsset);
|
||||||
|
@(_ServiceWorkerStaticWebAsset)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_WriteServiceWorkerAssetsManifest"
|
||||||
|
DependsOnTargets="_ComputeServiceWorkerAssets;ResolveStaticWebAssetsInputs">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_ServiceWorkItem Include="@(StaticWebAsset)" Exclude="$(_ServiceWorkerAssetsManifestFullPath);@(_ServiceWorkerStaticWebAsset)">
|
||||||
|
<AssetUrl>$([System.String]::Copy('$([System.String]::Copy('%(StaticWebAsset.BasePath)').TrimEnd('/'))/%(StaticWebAsset.RelativePath)').Replace('\','/').TrimStart('/'))</AssetUrl>
|
||||||
|
</_ServiceWorkItem>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<GenerateServiceWorkerAssetsManifest
|
||||||
|
Version="$(ServiceWorkerAssetsManifestVersion)"
|
||||||
|
Assets="@(_ServiceWorkItem)"
|
||||||
|
OutputPath="$(_ServiceWorkerAssetsManifestIntermediateOutputPath)">
|
||||||
|
<Output TaskParameter="CalculatedVersion" PropertyName="_ServiceWorkerAssetsManifestVersion" />
|
||||||
|
</GenerateServiceWorkerAssetsManifest>
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="%(_ServiceWorkerIntermediateFile.ContentSourcePath)"
|
||||||
|
DestinationFiles="%(_ServiceWorkerIntermediateFile.Identity)" />
|
||||||
|
|
||||||
|
<WriteLinesToFile
|
||||||
|
File="%(_ServiceWorkerIntermediateFile.Identity)"
|
||||||
|
Lines="/* Manifest version: $(_ServiceWorkerAssetsManifestVersion) */"
|
||||||
|
Condition="'$(_ServiceWorkerAssetsManifestVersion)' != ''" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<FileWrites Include="@(_ServiceWorkerIntermediateFile)" />
|
||||||
|
<FileWrites Include="$(_ServiceWorkerAssetsManifestIntermediateOutputPath)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_BlazorStaticAssetsCopyFilesToOutputDirectory" AfterTargets="CopyFilesToOutputDirectory" DependsOnTargets="_WriteServiceWorkerAssetsManifest">
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(_ManifestStaticWebAsset);@(_ServiceWorkerStaticWebAsset)"
|
||||||
|
DestinationFiles="$(OutDir)wwwroot\%(RelativePath)"
|
||||||
|
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
|
||||||
|
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
|
||||||
|
Retries="$(CopyRetryCount)"
|
||||||
|
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
|
||||||
|
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)"
|
||||||
|
Condition="Exists('%(Identity)')">
|
||||||
|
|
||||||
|
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
|
||||||
|
</Copy>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_OmitServiceWorkerContent"
|
||||||
|
BeforeTargets="AssignTargetPaths;ResolveCurrentProjectStaticWebAssetsInputs">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- Don't emit the service worker source files to the output -->
|
||||||
|
<Content Remove="@(ServiceWorker)" />
|
||||||
|
<Content Remove="@(ServiceWorker->'%(PublishedContent)')" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_GenerateServiceWorkerFileForPublish"
|
||||||
|
BeforeTargets="_BlazorCompressPublishFiles"
|
||||||
|
AfterTargets="_ProcessPublishFilesForBlazor">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ServiceWorkerAssetsManifestPublishIntermediateOutputPath>$(IntermediateOutputPath)publish-$(ServiceWorkerAssetsManifest)</_ServiceWorkerAssetsManifestPublishIntermediateOutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_ServiceWorkerIntermediatePublishFile Include="$(IntermediateOutputPath)serviceworkers\%(FileName).publish%(Extension)">
|
||||||
|
<ContentSourcePath Condition="'%(ServiceWorker.PublishedContent)' != ''">%(ServiceWorker.PublishedContent)</ContentSourcePath>
|
||||||
|
<ContentSourcePath Condition="'%(ServiceWorker.PublishedContent)' == ''">%(ServiceWorker.Identity)</ContentSourcePath>
|
||||||
|
<RelativePath>%(ServiceWorker.Identity)</RelativePath>
|
||||||
|
</_ServiceWorkerIntermediatePublishFile>
|
||||||
|
|
||||||
|
<_ServiceWorkerPublishFile Include="@(ResolvedFileToPublish)" Condition="$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))">
|
||||||
|
<AssetUrl>$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').TrimStart('/'))</AssetUrl>
|
||||||
|
<AssetUrl>$([System.String]::Copy('%(RelativePath)').Replace('\','/').Substring(8))</AssetUrl>
|
||||||
|
</_ServiceWorkerPublishFile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<GenerateServiceWorkerAssetsManifest
|
||||||
|
Version="$(ServiceWorkerAssetsManifestVersion)"
|
||||||
|
Assets="@(_ServiceWorkerPublishFile)"
|
||||||
|
OutputPath="$(_ServiceWorkerAssetsManifestPublishIntermediateOutputPath)">
|
||||||
|
|
||||||
|
<Output TaskParameter="CalculatedVersion" PropertyName="_ServiceWorkerPublishAssetsManifestVersion" />
|
||||||
|
</GenerateServiceWorkerAssetsManifest>
|
||||||
|
|
||||||
|
<Copy SourceFiles="%(_ServiceWorkerIntermediatePublishFile.ContentSourcePath)"
|
||||||
|
DestinationFiles="%(_ServiceWorkerIntermediatePublishFile.Identity)" />
|
||||||
|
|
||||||
|
<WriteLinesToFile
|
||||||
|
File="%(_ServiceWorkerIntermediatePublishFile.Identity)"
|
||||||
|
Lines="/* Manifest version: $(_ServiceWorkerPublishAssetsManifestVersion) */" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ResolvedFileToPublish
|
||||||
|
Include="@(_ServiceWorkerIntermediatePublishFile)"
|
||||||
|
CopyToPublishDirectory="PreserveNewest"
|
||||||
|
RelativePath="%(_ServiceWorkerIntermediatePublishFile.RelativePath)"
|
||||||
|
ExcludeFromSingleFile="true" />
|
||||||
|
|
||||||
|
<ResolvedFileToPublish
|
||||||
|
Include="$(_ServiceWorkerAssetsManifestPublishIntermediateOutputPath)"
|
||||||
|
CopyToPublishDirectory="PreserveNewest"
|
||||||
|
RelativePath="wwwroot\$(ServiceWorkerAssetsManifest)"
|
||||||
|
ExcludeFromSingleFile="true" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
// 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.IO;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly
|
||||||
|
{
|
||||||
|
public class BlazorReadSatelliteAssemblyFileTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void WritesAndReadsRoundTrip()
|
||||||
|
{
|
||||||
|
// Arrange/Act
|
||||||
|
var tempFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||||
|
|
||||||
|
var writer = new BlazorWriteSatelliteAssemblyFile
|
||||||
|
{
|
||||||
|
BuildEngine = Mock.Of<IBuildEngine>(),
|
||||||
|
WriteFile = new TaskItem(tempFile),
|
||||||
|
SatelliteAssembly = new[]
|
||||||
|
{
|
||||||
|
new TaskItem("Resources.fr.dll", new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["Culture"] = "fr",
|
||||||
|
["DestinationSubDirectory"] = "fr\\",
|
||||||
|
}),
|
||||||
|
new TaskItem("Resources.ja-jp.dll", new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["Culture"] = "ja-jp",
|
||||||
|
["DestinationSubDirectory"] = "ja-jp\\",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var reader = new BlazorReadSatelliteAssemblyFile
|
||||||
|
{
|
||||||
|
BuildEngine = Mock.Of<IBuildEngine>(),
|
||||||
|
ReadFile = new TaskItem(tempFile),
|
||||||
|
};
|
||||||
|
|
||||||
|
writer.Execute();
|
||||||
|
|
||||||
|
Assert.True(File.Exists(tempFile), "Write should have succeeded.");
|
||||||
|
|
||||||
|
reader.Execute();
|
||||||
|
|
||||||
|
Assert.Collection(
|
||||||
|
reader.SatelliteAssembly,
|
||||||
|
assembly =>
|
||||||
|
{
|
||||||
|
Assert.Equal("Resources.fr.dll", assembly.ItemSpec);
|
||||||
|
Assert.Equal("fr", assembly.GetMetadata("Culture"));
|
||||||
|
Assert.Equal("fr\\", assembly.GetMetadata("DestinationSubDirectory"));
|
||||||
|
},
|
||||||
|
assembly =>
|
||||||
|
{
|
||||||
|
Assert.Equal("Resources.ja-jp.dll", assembly.ItemSpec);
|
||||||
|
Assert.Equal("ja-jp", assembly.GetMetadata("Culture"));
|
||||||
|
Assert.Equal("ja-jp\\", assembly.GetMetadata("DestinationSubDirectory"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,195 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization.Json;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly
|
||||||
|
{
|
||||||
|
public class GenerateBlazorWebAssemblyBootJsonTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void GroupsResourcesByType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var taskInstance = new GenerateBlazorWebAssemblyBootJson
|
||||||
|
{
|
||||||
|
AssemblyPath = "MyApp.Entrypoint.dll",
|
||||||
|
Resources = new[]
|
||||||
|
{
|
||||||
|
CreateResourceTaskItem(
|
||||||
|
("FileName", "My.Assembly1"),
|
||||||
|
("Extension", ".dll"),
|
||||||
|
("FileHash", "abcdefghikjlmnopqrstuvwxyz")),
|
||||||
|
|
||||||
|
CreateResourceTaskItem(
|
||||||
|
("FileName", "My.Assembly2"),
|
||||||
|
("Extension", ".dll"),
|
||||||
|
("FileHash", "012345678901234567890123456789")),
|
||||||
|
|
||||||
|
CreateResourceTaskItem(
|
||||||
|
("FileName", "SomePdb"),
|
||||||
|
("Extension", ".pdb"),
|
||||||
|
("FileHash", "pdbhashpdbhashpdbhash")),
|
||||||
|
|
||||||
|
CreateResourceTaskItem(
|
||||||
|
("FileName", "My.Assembly1"),
|
||||||
|
("Extension", ".pdb"),
|
||||||
|
("FileHash", "pdbdefghikjlmnopqrstuvwxyz")),
|
||||||
|
|
||||||
|
CreateResourceTaskItem(
|
||||||
|
("FileName", "some-runtime-file"),
|
||||||
|
("FileHash", "runtimehashruntimehash"),
|
||||||
|
("AssetType", "native")),
|
||||||
|
|
||||||
|
CreateResourceTaskItem(
|
||||||
|
("FileName", "satellite-assembly1"),
|
||||||
|
("Extension", ".dll"),
|
||||||
|
("FileHash", "hashsatelliteassembly1"),
|
||||||
|
("Culture", "en-GB")),
|
||||||
|
|
||||||
|
CreateResourceTaskItem(
|
||||||
|
("FileName", "satellite-assembly2"),
|
||||||
|
("Extension", ".dll"),
|
||||||
|
("FileHash", "hashsatelliteassembly2"),
|
||||||
|
("Culture", "fr")),
|
||||||
|
|
||||||
|
CreateResourceTaskItem(
|
||||||
|
("FileName", "satellite-assembly3"),
|
||||||
|
("Extension", ".dll"),
|
||||||
|
("FileHash", "hashsatelliteassembly3"),
|
||||||
|
("Culture", "en-GB")),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
taskInstance.WriteBootJson(stream, "MyEntrypointAssembly");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var parsedContent = ParseBootData(stream);
|
||||||
|
Assert.Equal("MyEntrypointAssembly", parsedContent.entryAssembly);
|
||||||
|
|
||||||
|
var resources = parsedContent.resources.assembly;
|
||||||
|
Assert.Equal(2, resources.Count);
|
||||||
|
Assert.Equal("sha256-abcdefghikjlmnopqrstuvwxyz", resources["My.Assembly1.dll"]);
|
||||||
|
Assert.Equal("sha256-012345678901234567890123456789", resources["My.Assembly2.dll"]);
|
||||||
|
|
||||||
|
resources = parsedContent.resources.pdb;
|
||||||
|
Assert.Equal(2, resources.Count);
|
||||||
|
Assert.Equal("sha256-pdbhashpdbhashpdbhash", resources["SomePdb.pdb"]);
|
||||||
|
Assert.Equal("sha256-pdbdefghikjlmnopqrstuvwxyz", resources["My.Assembly1.pdb"]);
|
||||||
|
|
||||||
|
resources = parsedContent.resources.runtime;
|
||||||
|
Assert.Single(resources);
|
||||||
|
Assert.Equal("sha256-runtimehashruntimehash", resources["some-runtime-file"]);
|
||||||
|
|
||||||
|
var satelliteResources = parsedContent.resources.satelliteResources;
|
||||||
|
Assert.Collection(
|
||||||
|
satelliteResources.OrderBy(kvp => kvp.Key),
|
||||||
|
kvp =>
|
||||||
|
{
|
||||||
|
Assert.Equal("en-GB", kvp.Key);
|
||||||
|
Assert.Collection(
|
||||||
|
kvp.Value.OrderBy(item => item.Key),
|
||||||
|
item =>
|
||||||
|
{
|
||||||
|
Assert.Equal("en-GB/satellite-assembly1.dll", item.Key);
|
||||||
|
Assert.Equal("sha256-hashsatelliteassembly1", item.Value);
|
||||||
|
},
|
||||||
|
item =>
|
||||||
|
{
|
||||||
|
Assert.Equal("en-GB/satellite-assembly3.dll", item.Key);
|
||||||
|
Assert.Equal("sha256-hashsatelliteassembly3", item.Value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
kvp =>
|
||||||
|
{
|
||||||
|
Assert.Equal("fr", kvp.Key);
|
||||||
|
Assert.Collection(
|
||||||
|
kvp.Value.OrderBy(item => item.Key),
|
||||||
|
item =>
|
||||||
|
{
|
||||||
|
Assert.Equal("fr/satellite-assembly2.dll", item.Key);
|
||||||
|
Assert.Equal("sha256-hashsatelliteassembly2", item.Value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(false)]
|
||||||
|
[InlineData(true)]
|
||||||
|
public void CanSpecifyCacheBootResources(bool flagValue)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var taskInstance = new GenerateBlazorWebAssemblyBootJson { CacheBootResources = flagValue };
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
taskInstance.WriteBootJson(stream, "MyEntrypointAssembly");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var parsedContent = ParseBootData(stream);
|
||||||
|
Assert.Equal(flagValue, parsedContent.cacheBootResources);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(false)]
|
||||||
|
[InlineData(true)]
|
||||||
|
public void CanSpecifyDebugBuild(bool flagValue)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var taskInstance = new GenerateBlazorWebAssemblyBootJson { DebugBuild = flagValue };
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
taskInstance.WriteBootJson(stream, "MyEntrypointAssembly");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var parsedContent = ParseBootData(stream);
|
||||||
|
Assert.Equal(flagValue, parsedContent.debugBuild);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(false)]
|
||||||
|
[InlineData(true)]
|
||||||
|
public void CanSpecifyLinkerEnabled(bool flagValue)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var taskInstance = new GenerateBlazorWebAssemblyBootJson { LinkerEnabled = flagValue };
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
taskInstance.WriteBootJson(stream, "MyEntrypointAssembly");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var parsedContent = ParseBootData(stream);
|
||||||
|
Assert.Equal(flagValue, parsedContent.linkerEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BootJsonData ParseBootData(Stream stream)
|
||||||
|
{
|
||||||
|
stream.Position = 0;
|
||||||
|
var serializer = new DataContractJsonSerializer(
|
||||||
|
typeof(BootJsonData),
|
||||||
|
new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true });
|
||||||
|
return (BootJsonData)serializer.ReadObject(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ITaskItem CreateResourceTaskItem(params (string key, string value)[] values)
|
||||||
|
{
|
||||||
|
var mock = new Mock<ITaskItem>();
|
||||||
|
|
||||||
|
foreach (var (key, value) in values)
|
||||||
|
{
|
||||||
|
mock.Setup(m => m.GetMetadata(key)).Returns(value);
|
||||||
|
}
|
||||||
|
return mock.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Build.Utilities.Core" />
|
||||||
|
<Reference Include="Microsoft.NET.Sdk.BlazorWebAssembly" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<Project>
|
||||||
|
<Import Project="Before.Directory.Build.props" Condition="Exists('Before.Directory.Build.props')" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!--
|
||||||
|
In the case that a user is building a sample directly the MicrosoftNetCompilersToolsetPackagerVersion will not be provided.
|
||||||
|
We'll fall back to whatever the current SDK provides in regards to Roslyn's Microsoft.Net.Compilers.Toolset.
|
||||||
|
-->
|
||||||
|
<BuildingTestAppsIndependently>false</BuildingTestAppsIndependently>
|
||||||
|
<BuildingTestAppsIndependently Condition="'$(MicrosoftNetCompilersToolsetPackageVersion)' == ''">true</BuildingTestAppsIndependently>
|
||||||
|
|
||||||
|
<!-- Do not resolve Reference ItemGroup since it has a different semantic meaning in Razor test apps -->
|
||||||
|
<EnableCustomReferenceResolution>false</EnableCustomReferenceResolution>
|
||||||
|
|
||||||
|
<DefaultNetCoreTargetFramework>net5.0</DefaultNetCoreTargetFramework>
|
||||||
|
|
||||||
|
<RepoRoot Condition="'$(RepoRoot)' == ''">$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, 'AspNetCore.sln'))\</RepoRoot>
|
||||||
|
|
||||||
|
<RazorSdkCurrentVersionProps>$(RepoRoot)src\Razor\Microsoft.NET.Sdk.Razor\src\build\netstandard2.0\Sdk.Razor.CurrentVersion.props</RazorSdkCurrentVersionProps>
|
||||||
|
<RazorSdkCurrentVersionTargets>$(RepoRoot)src\Razor\Microsoft.NET.Sdk.Razor\src\build\netstandard2.0\Sdk.Razor.CurrentVersion.targets</RazorSdkCurrentVersionTargets>
|
||||||
|
<RazorSdkArtifactsDirectory>$(RepoRoot)artifacts\bin\Microsoft.NET.Sdk.Razor\</RazorSdkArtifactsDirectory>
|
||||||
|
<BlazorWebAssemblySdkArtifactsDirectory>$(RepoRoot)artifacts\bin\Microsoft.NET.Sdk.BlazorWebAssembly\</BlazorWebAssemblySdkArtifactsDirectory>
|
||||||
|
<BlazorWebAssemblyJSPath>$(MSBuildThisFileDirectory)blazor.webassembly.js</BlazorWebAssemblyJSPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(RepoRoot)eng\Versions.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- Reset version prefix to 1.0.0 for test projects -->
|
||||||
|
<VersionPrefix>1.0.0</VersionPrefix>
|
||||||
|
|
||||||
|
<!-- Turn down the compression level for brotli -->
|
||||||
|
<_BlazorBrotliCompressionLevel>NoCompression</_BlazorBrotliCompressionLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- Have the SDK treat the MvcShim as an MVC assembly -->
|
||||||
|
<_MvcAssemblyName Include="Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="$(BuildingTestAppsIndependently) == 'false'">
|
||||||
|
<PackageReference Include="Microsoft.Net.Compilers.Toolset"
|
||||||
|
Version="$(MicrosoftNetCompilersToolsetPackageVersion)"
|
||||||
|
PrivateAssets="all"
|
||||||
|
IsImplicitlyDefined="true" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Import Project="After.Directory.Build.props" Condition="Exists('After.Directory.Build.props')" />
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)' ">$(MicrosoftNETCoreAppRuntimeVersion)</RuntimeFrameworkVersion>
|
||||||
|
<!-- aspnet/BuildTools#662 Don't police what version of NetCoreApp we use -->
|
||||||
|
<NETCoreAppMaximumVersion>99.9</NETCoreAppMaximumVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\blazorhosted\blazorhosted.csproj" />
|
||||||
|
<ProjectReference Include="..\blazorhosted-rid\blazorhosted-rid.csproj" />
|
||||||
|
<ProjectReference Include="..\blazorwasm\blazorwasm.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Test file
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||||
|
|
||||||
|
<Import Project="$(RepoRoot)src\Components\WebAssembly\Sdk\src\Sdk\Sdk.props" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<UseBlazorWebAssembly>true</UseBlazorWebAssembly>
|
|
||||||
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
|
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
|
||||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
|
||||||
<RazorSdkDirectoryRoot>$(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\</RazorSdkDirectoryRoot>
|
<RazorSdkDirectoryRoot>$(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\</RazorSdkDirectoryRoot>
|
||||||
|
<BlazorWebAssemblySdkDirectoryRoot>$(BlazorWebAssemblySdkArtifactsDirectory)$(Configuration)\sdk-output\</BlazorWebAssemblySdkDirectoryRoot>
|
||||||
<ServiceWorkerAssetsManifest>custom-service-worker-assets.js</ServiceWorkerAssetsManifest>
|
<ServiceWorkerAssetsManifest>custom-service-worker-assets.js</ServiceWorkerAssetsManifest>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
@ -50,4 +52,6 @@
|
||||||
<ServiceWorker Include="wwwroot\serviceworkers\my-service-worker.js" PublishedContent="wwwroot\serviceworkers\my-prod-service-worker.js" />
|
<ServiceWorker Include="wwwroot\serviceworkers\my-service-worker.js" PublishedContent="wwwroot\serviceworkers\my-prod-service-worker.js" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Import Project="$(RepoRoot)src\Components\WebAssembly\Sdk\src\Sdk\Sdk.targets" />
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.Extensions.CommandLineUtils;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly.Tools
|
||||||
|
{
|
||||||
|
internal class Application : CommandLineApplication
|
||||||
|
{
|
||||||
|
public Application(
|
||||||
|
CancellationToken cancellationToken,
|
||||||
|
TextWriter output = null,
|
||||||
|
TextWriter error = null)
|
||||||
|
{
|
||||||
|
CancellationToken = cancellationToken;
|
||||||
|
Out = output ?? Out;
|
||||||
|
Error = error ?? Error;
|
||||||
|
|
||||||
|
Name = "BlazorWebAssembly.Tools";
|
||||||
|
FullName = "Microsoft Blazor WebAssembly SDK tool";
|
||||||
|
Description = "CLI for Blazor WebAssembly operations.";
|
||||||
|
ShortVersionGetter = GetInformationalVersion;
|
||||||
|
|
||||||
|
HelpOption("-?|-h|--help");
|
||||||
|
|
||||||
|
Commands.Add(new BrotliCompressCommand(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CancellationToken CancellationToken { get; }
|
||||||
|
|
||||||
|
public new int Execute(params string[] args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return base.Execute(ExpandResponseFiles(args));
|
||||||
|
}
|
||||||
|
catch (AggregateException ex) when (ex.InnerException != null)
|
||||||
|
{
|
||||||
|
foreach (var innerException in ex.Flatten().InnerExceptions)
|
||||||
|
{
|
||||||
|
Error.WriteLine(innerException.Message);
|
||||||
|
Error.WriteLine(innerException.StackTrace);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
catch (CommandParsingException ex)
|
||||||
|
{
|
||||||
|
// Don't show a call stack when we have unneeded arguments, just print the error message.
|
||||||
|
// The code that throws this exception will print help, so no need to do it here.
|
||||||
|
Error.WriteLine(ex.Message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// This is a cancellation, not a failure.
|
||||||
|
Error.WriteLine("Cancelled");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Error.WriteLine(ex.Message);
|
||||||
|
Error.WriteLine(ex.StackTrace);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetInformationalVersion()
|
||||||
|
{
|
||||||
|
var assembly = typeof(Application).GetTypeInfo().Assembly;
|
||||||
|
var attribute = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
|
||||||
|
return attribute.InformationalVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] ExpandResponseFiles(string[] args)
|
||||||
|
{
|
||||||
|
var expandedArgs = new List<string>();
|
||||||
|
foreach (var arg in args)
|
||||||
|
{
|
||||||
|
if (!arg.StartsWith("@", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
expandedArgs.Add(arg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var fileName = arg.Substring(1);
|
||||||
|
expandedArgs.AddRange(File.ReadLines(fileName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expandedArgs.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.CommandLineUtils;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly.Tools
|
||||||
|
{
|
||||||
|
internal class BrotliCompressCommand : CommandLineApplication
|
||||||
|
{
|
||||||
|
public BrotliCompressCommand(Application parent)
|
||||||
|
: base(throwOnUnexpectedArg: true)
|
||||||
|
{
|
||||||
|
base.Parent = parent;
|
||||||
|
Name = "brotli";
|
||||||
|
Sources = Option("-s", "files to compress", CommandOptionType.MultipleValue);
|
||||||
|
Outputs = Option("-o", "Output file path", CommandOptionType.MultipleValue);
|
||||||
|
CompressionLevelOption = Option("-c", "Compression level", CommandOptionType.SingleValue);
|
||||||
|
|
||||||
|
Invoke = () => Execute().GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandOption Sources { get; }
|
||||||
|
|
||||||
|
public CommandOption Outputs { get; }
|
||||||
|
|
||||||
|
public CommandOption CompressionLevelOption { get; }
|
||||||
|
|
||||||
|
public CompressionLevel CompressionLevel { get; private set; } = CompressionLevel.Optimal;
|
||||||
|
|
||||||
|
private Task<int> Execute()
|
||||||
|
{
|
||||||
|
if (!ValidateArguments())
|
||||||
|
{
|
||||||
|
ShowHelp();
|
||||||
|
return Task.FromResult(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExecuteCoreAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ValidateArguments()
|
||||||
|
{
|
||||||
|
if (Sources.Values.Count != Outputs.Values.Count)
|
||||||
|
{
|
||||||
|
Error.WriteLine($"{Sources.Description} has {Sources.Values.Count}, but {Outputs.Description} has {Outputs.Values.Count} values.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CompressionLevelOption.HasValue())
|
||||||
|
{
|
||||||
|
if (!Enum.TryParse<CompressionLevel>(CompressionLevelOption.Value(), out var value))
|
||||||
|
{
|
||||||
|
Error.WriteLine($"Invalid option {CompressionLevelOption.Value()} for {CompressionLevelOption.Template}.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressionLevel = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task<int> ExecuteCoreAsync()
|
||||||
|
{
|
||||||
|
Parallel.For(0, Sources.Values.Count, i =>
|
||||||
|
{
|
||||||
|
var source = Sources.Values[i];
|
||||||
|
var output = Outputs.Values[i];
|
||||||
|
|
||||||
|
using var sourceStream = File.OpenRead(source);
|
||||||
|
using var fileStream = new FileStream(output, FileMode.Create);
|
||||||
|
|
||||||
|
using var stream = new BrotliStream(fileStream, CompressionLevel);
|
||||||
|
|
||||||
|
sourceStream.CopyTo(stream);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly.Tools
|
||||||
|
{
|
||||||
|
internal static class DebugMode
|
||||||
|
{
|
||||||
|
public static void HandleDebugSwitch(ref string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length > 0 && string.Equals("--debug", args[0], StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
args = args.Skip(1).ToArray();
|
||||||
|
|
||||||
|
Console.WriteLine("Waiting for debugger in pid: {0}", Process.GetCurrentProcess().Id);
|
||||||
|
while (!Debugger.IsAttached)
|
||||||
|
{
|
||||||
|
Thread.Sleep(TimeSpan.FromSeconds(3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<IsShipping>false</IsShipping>
|
||||||
|
<DisablePubternalApiCheck>true</DisablePubternalApiCheck>
|
||||||
|
|
||||||
|
<UseAppHost>false</UseAppHost>
|
||||||
|
<RuntimeIdentifier />
|
||||||
|
|
||||||
|
<!-- Need to build this project in source build -->
|
||||||
|
<ExcludeFromSourceBuild>false</ExcludeFromSourceBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="$(SharedSourceRoot)CommandLineUtils\**\*.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// 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 Microsoft.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace Microsoft.NET.Sdk.BlazorWebAssembly.Tools
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
public static int Main(string[] args)
|
||||||
|
{
|
||||||
|
DebugMode.HandleDebugSwitch(ref args);
|
||||||
|
|
||||||
|
var cancel = new CancellationTokenSource();
|
||||||
|
Console.CancelKeyPress += (sender, e) => { cancel.Cancel(); };
|
||||||
|
|
||||||
|
var application = new Application(
|
||||||
|
cancel.Token,
|
||||||
|
Console.Out,
|
||||||
|
Console.Error);
|
||||||
|
|
||||||
|
application.Commands.Add(new BrotliCompressCommand(application));
|
||||||
|
|
||||||
|
return application.Execute(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"rollForwardOnNoCandidateFx": 2
|
||||||
|
}
|
||||||
|
|
@ -565,6 +565,19 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
AssertDidNotLog("I'm not happening...");
|
AssertDidNotLog("I'm not happening...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void OnNavigate_CanRenderUIForExceptions()
|
||||||
|
{
|
||||||
|
var app = Browser.MountTestComponent<TestRouterWithOnNavigate>();
|
||||||
|
|
||||||
|
// Navigating from one page to another should
|
||||||
|
// cancel the previous OnNavigate Task
|
||||||
|
SetUrlViaPushState("/Other");
|
||||||
|
|
||||||
|
var errorUiElem = Browser.Exists(By.Id("blazor-error-ui"), TimeSpan.FromSeconds(10));
|
||||||
|
Assert.NotNull(errorUiElem);
|
||||||
|
}
|
||||||
|
|
||||||
private long BrowserScrollY
|
private long BrowserScrollY
|
||||||
{
|
{
|
||||||
get => (long)((IJavaScriptExecutor)Browser).ExecuteScript("return window.scrollY");
|
get => (long)((IJavaScriptExecutor)Browser).ExecuteScript("return window.scrollY");
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@
|
||||||
private Dictionary<string, Func<NavigationContext, Task>> preNavigateTasks = new Dictionary<string, Func<NavigationContext, Task>>()
|
private Dictionary<string, Func<NavigationContext, Task>> preNavigateTasks = new Dictionary<string, Func<NavigationContext, Task>>()
|
||||||
{
|
{
|
||||||
{ "LongPage1", new Func<NavigationContext, Task>(TestLoadingPageShows) },
|
{ "LongPage1", new Func<NavigationContext, Task>(TestLoadingPageShows) },
|
||||||
{ "LongPage2", new Func<NavigationContext, Task>(TestOnNavCancel) }
|
{ "LongPage2", new Func<NavigationContext, Task>(TestOnNavCancel) },
|
||||||
|
{ "Other", new Func<NavigationContext, Task>(TestOnNavException) }
|
||||||
};
|
};
|
||||||
|
|
||||||
private async Task OnNavigateAsync(NavigationContext args)
|
private async Task OnNavigateAsync(NavigationContext args)
|
||||||
|
|
@ -43,4 +44,10 @@
|
||||||
await Task.Delay(2000, args.CancellationToken);
|
await Task.Delay(2000, args.CancellationToken);
|
||||||
Console.WriteLine("I'm not happening...");
|
Console.WriteLine("I'm not happening...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task TestOnNavException(NavigationContext args)
|
||||||
|
{
|
||||||
|
await Task.CompletedTask;
|
||||||
|
throw new Exception("This is an uncaught exception.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<!--
|
<!--
|
||||||
|
|
@ -13,8 +13,11 @@
|
||||||
|
|
||||||
<!-- Tests do not work on Helix yet -->
|
<!-- Tests do not work on Helix yet -->
|
||||||
<BuildHelixPayload>false</BuildHelixPayload>
|
<BuildHelixPayload>false</BuildHelixPayload>
|
||||||
|
<TestAppsRoot>$(MSBuildProjectDirectory)\..\..\test\testassets\</TestAppsRoot>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(SharedSourceRoot)MSBuild.Testing\MSBuild.Testing.targets" />
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
|
<None Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
@ -24,49 +27,6 @@
|
||||||
<Reference Include="Microsoft.Extensions.DependencyModel" />
|
<Reference Include="Microsoft.Extensions.DependencyModel" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
|
||||||
<_Parameter1>Testing.AdditionalRestoreSources</_Parameter1>
|
|
||||||
<_Parameter2>$(MSBuildThisFileDirectory)..\testassets\PregeneratedPackages</_Parameter2>
|
|
||||||
</AssemblyAttribute>
|
|
||||||
|
|
||||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
|
||||||
<_Parameter1>ArtifactsLogDir</_Parameter1>
|
|
||||||
<_Parameter2>$([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'log', '$(_BuildConfig)'))</_Parameter2>
|
|
||||||
</AssemblyAttribute>
|
|
||||||
|
|
||||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
|
||||||
<_Parameter1>ProcDumpToolPath</_Parameter1>
|
|
||||||
<_Parameter2>$(ProcDumpPath)</_Parameter2>
|
|
||||||
</AssemblyAttribute>
|
|
||||||
|
|
||||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
|
||||||
<_Parameter1>Testing.RepoRoot</_Parameter1>
|
|
||||||
<_Parameter2>$(RepoRoot)</_Parameter2>
|
|
||||||
</AssemblyAttribute>
|
|
||||||
|
|
||||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
|
||||||
<_Parameter1>MicrosoftNETCoreAppRuntimeVersion</_Parameter1>
|
|
||||||
<_Parameter2>$(MicrosoftNETCoreAppRuntimeVersion)</_Parameter2>
|
|
||||||
</AssemblyAttribute>
|
|
||||||
|
|
||||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
|
||||||
<_Parameter1>DefaultNetCoreTargetFramework</_Parameter1>
|
|
||||||
<_Parameter2>$(DefaultNetCoreTargetFramework)</_Parameter2>
|
|
||||||
</AssemblyAttribute>
|
|
||||||
|
|
||||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
|
||||||
<_Parameter1>MicrosoftNetCompilersToolsetPackageVersion</_Parameter1>
|
|
||||||
<_Parameter2>$(MicrosoftNetCompilersToolsetPackageVersion)</_Parameter2>
|
|
||||||
</AssemblyAttribute>
|
|
||||||
|
|
||||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
|
||||||
<_Parameter1>RazorSdkDirectoryRoot</_Parameter1>
|
|
||||||
<_Parameter2>$(ArtifactsBinDir)Microsoft.NET.Sdk.Razor\$(Configuration)\sdk-output\</_Parameter2>
|
|
||||||
</AssemblyAttribute>
|
|
||||||
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="rzc" />
|
<Reference Include="rzc" />
|
||||||
<ProjectReference Include="..\..\test\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib.csproj" />
|
<ProjectReference Include="..\..\test\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib.csproj" />
|
||||||
|
|
|
||||||
|
|
@ -66,14 +66,9 @@
|
||||||
<_DefaultProjectRoot>$([System.IO.Path]::GetFullPath($(_DefaultProjectFilter)))</_DefaultProjectRoot>
|
<_DefaultProjectRoot>$([System.IO.Path]::GetFullPath($(_DefaultProjectFilter)))</_DefaultProjectRoot>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<_ContentRootProjectReferencesUnfiltered
|
|
||||||
Include="@(ReferencePath)"
|
|
||||||
Condition="'%(ReferencePath.ReferenceSourceTarget)' == 'ProjectReference'" />
|
|
||||||
<_ContentRootProjectReferencesFilter
|
|
||||||
Include="@(_ContentRootProjectReferencesUnfiltered->StartsWith('$(_DefaultProjectRoot)'))" />
|
|
||||||
<_ContentRootProjectReferences
|
<_ContentRootProjectReferences
|
||||||
Include="@(_ContentRootProjectReferencesFilter)"
|
Include="@(ReferencePath)"
|
||||||
Condition="'%(Identity)' == 'True'" />
|
Condition="'%(ReferencePath.ReferenceSourceTarget)' == 'ProjectReference' AND $([System.String]::Copy(%(ReferencePath.MSBuildSourceProjectFile)).StartsWith('$(_DefaultProjectRoot)'))" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,12 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
|
|
||||||
public static string RazorSdkDirectoryRoot => TestAssemblyMetadata.SingleOrDefault(a => a.Key == "RazorSdkDirectoryRoot").Value;
|
public static string RazorSdkDirectoryRoot => TestAssemblyMetadata.SingleOrDefault(a => a.Key == "RazorSdkDirectoryRoot").Value;
|
||||||
|
|
||||||
|
public static string BlazorWebAssemblySdkDirectoryRoot => TestAssemblyMetadata.SingleOrDefault(a => a.Key == "BlazorWebAssemblySdkDirectoryRoot").Value;
|
||||||
|
|
||||||
public static string RepoRoot => TestAssemblyMetadata.SingleOrDefault(a => a.Key == "Testing.RepoRoot").Value;
|
public static string RepoRoot => TestAssemblyMetadata.SingleOrDefault(a => a.Key == "Testing.RepoRoot").Value;
|
||||||
|
|
||||||
public static string DefaultNetCoreTargetFramework => TestAssemblyMetadata.SingleOrDefault(a => a.Key == "DefaultNetCoreTargetFramework").Value;
|
public static string DefaultNetCoreTargetFramework => TestAssemblyMetadata.SingleOrDefault(a => a.Key == "DefaultNetCoreTargetFramework").Value;
|
||||||
|
|
||||||
|
public static string TestAppsRoot => TestAssemblyMetadata.SingleOrDefault(a => a.Key == "TestAppsRoot").Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
<Project>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>ArtifactsLogDir</_Parameter1>
|
||||||
|
<_Parameter2>$([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'log', '$(_BuildConfig)'))</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>ProcDumpToolPath</_Parameter1>
|
||||||
|
<_Parameter2>$(ProcDumpPath)</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>Testing.RepoRoot</_Parameter1>
|
||||||
|
<_Parameter2>$(RepoRoot)</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>MicrosoftNETCoreAppRuntimeVersion</_Parameter1>
|
||||||
|
<_Parameter2>$(MicrosoftNETCoreAppRuntimeVersion)</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>DefaultNetCoreTargetFramework</_Parameter1>
|
||||||
|
<_Parameter2>$(DefaultNetCoreTargetFramework)</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>MicrosoftNetCompilersToolsetPackageVersion</_Parameter1>
|
||||||
|
<_Parameter2>$(MicrosoftNetCompilersToolsetPackageVersion)</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>RazorSdkDirectoryRoot</_Parameter1>
|
||||||
|
<_Parameter2>$(ArtifactsBinDir)Microsoft.NET.Sdk.Razor\$(Configuration)\sdk-output\</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>BlazorWebAssemblySdkDirectoryRoot</_Parameter1>
|
||||||
|
<_Parameter2>$(ArtifactsBinDir)Microsoft.NET.Sdk.BlazorWebAssembly\$(Configuration)\sdk-output\</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
|
||||||
|
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||||
|
<_Parameter1>TestAppsRoot</_Parameter1>
|
||||||
|
<_Parameter2>$(TestAppsRoot)</_Parameter2>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)*.cs" LinkBase="Infrastructure" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -37,6 +37,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
$"/p:MicrosoftNETCoreAppRuntimeVersion={BuildVariables.MicrosoftNETCoreAppRuntimeVersion}",
|
$"/p:MicrosoftNETCoreAppRuntimeVersion={BuildVariables.MicrosoftNETCoreAppRuntimeVersion}",
|
||||||
$"/p:MicrosoftNetCompilersToolsetPackageVersion={BuildVariables.MicrosoftNetCompilersToolsetPackageVersion}",
|
$"/p:MicrosoftNetCompilersToolsetPackageVersion={BuildVariables.MicrosoftNetCompilersToolsetPackageVersion}",
|
||||||
$"/p:RazorSdkDirectoryRoot={BuildVariables.RazorSdkDirectoryRoot}",
|
$"/p:RazorSdkDirectoryRoot={BuildVariables.RazorSdkDirectoryRoot}",
|
||||||
|
$"/p:BlazorWebAssemblySdkDirectoryRoot={BuildVariables.BlazorWebAssemblySdkDirectoryRoot}",
|
||||||
$"/p:RepoRoot={BuildVariables.RepoRoot}",
|
$"/p:RepoRoot={BuildVariables.RepoRoot}",
|
||||||
$"/p:Configuration={project.Configuration}",
|
$"/p:Configuration={project.Configuration}",
|
||||||
$"/t:{target}",
|
$"/t:{target}",
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -49,12 +49,11 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
}
|
}
|
||||||
|
|
||||||
var repositoryRoot = BuildVariables.RepoRoot;
|
var repositoryRoot = BuildVariables.RepoRoot;
|
||||||
var solutionRoot = Path.Combine(repositoryRoot, "src", "Razor");
|
|
||||||
var binariesRoot = Path.GetDirectoryName(typeof(ProjectDirectory).Assembly.Location);
|
var binariesRoot = Path.GetDirectoryName(typeof(ProjectDirectory).Assembly.Location);
|
||||||
|
var testAppsRoot = BuildVariables.TestAppsRoot;
|
||||||
|
|
||||||
foreach (var project in new string[] { originalProjectName, }.Concat(additionalProjects))
|
foreach (var project in new string[] { originalProjectName, }.Concat(additionalProjects))
|
||||||
{
|
{
|
||||||
var testAppsRoot = Path.Combine(solutionRoot, "test", "testassets");
|
|
||||||
var projectRoot = Path.Combine(testAppsRoot, project);
|
var projectRoot = Path.Combine(testAppsRoot, project);
|
||||||
if (!Directory.Exists(projectRoot))
|
if (!Directory.Exists(projectRoot))
|
||||||
{
|
{
|
||||||
|
|
@ -146,6 +145,11 @@ $@"<Project>
|
||||||
.ForEach(file =>
|
.ForEach(file =>
|
||||||
{
|
{
|
||||||
var source = Path.Combine(testAppsRoot, file);
|
var source = Path.Combine(testAppsRoot, file);
|
||||||
|
if (!File.Exists(source))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var destination = Path.Combine(projectDestination, file);
|
var destination = Path.Combine(projectDestination, file);
|
||||||
File.Copy(source, destination);
|
File.Copy(source, destination);
|
||||||
});
|
});
|
||||||
|
|
@ -19,14 +19,14 @@ import okhttp3.*;
|
||||||
final class DefaultHttpClient extends HttpClient {
|
final class DefaultHttpClient extends HttpClient {
|
||||||
private OkHttpClient client = null;
|
private OkHttpClient client = null;
|
||||||
|
|
||||||
public DefaultHttpClient() {
|
public DefaultHttpClient(Action1<OkHttpClient.Builder> configureBuilder) {
|
||||||
this(0, null);
|
this(null, configureBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultHttpClient cloneWithTimeOut(int timeoutInMilliseconds) {
|
public DefaultHttpClient cloneWithTimeOut(int timeoutInMilliseconds) {
|
||||||
OkHttpClient newClient = client.newBuilder().readTimeout(timeoutInMilliseconds, TimeUnit.MILLISECONDS)
|
OkHttpClient newClient = client.newBuilder().readTimeout(timeoutInMilliseconds, TimeUnit.MILLISECONDS)
|
||||||
.build();
|
.build();
|
||||||
return new DefaultHttpClient(timeoutInMilliseconds, newClient);
|
return new DefaultHttpClient(newClient, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -36,7 +36,7 @@ final class DefaultHttpClient extends HttpClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultHttpClient(int timeoutInMilliseconds, OkHttpClient client) {
|
public DefaultHttpClient(OkHttpClient client, Action1<OkHttpClient.Builder> configureBuilder) {
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -90,9 +90,10 @@ final class DefaultHttpClient extends HttpClient {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (timeoutInMilliseconds > 0) {
|
if (configureBuilder != null) {
|
||||||
builder.readTimeout(timeoutInMilliseconds, TimeUnit.MILLISECONDS);
|
configureBuilder.invoke(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.client = builder.build();
|
this.client = builder.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A builder for configuring {@link HubConnection} instances.
|
* A builder for configuring {@link HubConnection} instances.
|
||||||
|
|
@ -20,6 +21,7 @@ public class HttpHubConnectionBuilder {
|
||||||
private long handshakeResponseTimeout = 0;
|
private long handshakeResponseTimeout = 0;
|
||||||
private Map<String, String> headers;
|
private Map<String, String> headers;
|
||||||
private TransportEnum transportEnum;
|
private TransportEnum transportEnum;
|
||||||
|
private Action1<OkHttpClient.Builder> configureBuilder;
|
||||||
|
|
||||||
HttpHubConnectionBuilder(String url) {
|
HttpHubConnectionBuilder(String url) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
|
|
@ -113,12 +115,25 @@ public class HttpHubConnectionBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a method that will be called when constructing the HttpClient to allow customization such as certificate validation, proxies, and cookies.
|
||||||
|
* By default the client will have a cookie jar added and a read timeout for LongPolling.
|
||||||
|
*
|
||||||
|
* @param configureBuilder Callback for configuring the OkHttpClient.Builder.
|
||||||
|
* @return This instance of the HttpHubConnectionBuilder.
|
||||||
|
*/
|
||||||
|
public HttpHubConnectionBuilder setHttpClientBuilderCallback(Action1<OkHttpClient.Builder> configureBuilder) {
|
||||||
|
this.configureBuilder = configureBuilder;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a new instance of {@link HubConnection}.
|
* Builds a new instance of {@link HubConnection}.
|
||||||
*
|
*
|
||||||
* @return A new instance of {@link HubConnection}.
|
* @return A new instance of {@link HubConnection}.
|
||||||
*/
|
*/
|
||||||
public HubConnection build() {
|
public HubConnection build() {
|
||||||
return new HubConnection(url, transport, skipNegotiate, httpClient, accessTokenProvider, handshakeResponseTimeout, headers, transportEnum);
|
return new HubConnection(url, transport, skipNegotiate, httpClient, accessTokenProvider,
|
||||||
|
handshakeResponseTimeout, headers, transportEnum, configureBuilder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import io.reactivex.Completable;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
import io.reactivex.subjects.*;
|
import io.reactivex.subjects.*;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A connection used to invoke hub methods on a SignalR Server.
|
* A connection used to invoke hub methods on a SignalR Server.
|
||||||
|
|
@ -126,7 +127,8 @@ public class HubConnection implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
HubConnection(String url, Transport transport, boolean skipNegotiate, HttpClient httpClient,
|
HubConnection(String url, Transport transport, boolean skipNegotiate, HttpClient httpClient,
|
||||||
Single<String> accessTokenProvider, long handshakeResponseTimeout, Map<String, String> headers, TransportEnum transportEnum) {
|
Single<String> accessTokenProvider, long handshakeResponseTimeout, Map<String, String> headers, TransportEnum transportEnum,
|
||||||
|
Action1<OkHttpClient.Builder> configureBuilder) {
|
||||||
if (url == null || url.isEmpty()) {
|
if (url == null || url.isEmpty()) {
|
||||||
throw new IllegalArgumentException("A valid url is required.");
|
throw new IllegalArgumentException("A valid url is required.");
|
||||||
}
|
}
|
||||||
|
|
@ -143,7 +145,7 @@ public class HubConnection implements AutoCloseable {
|
||||||
if (httpClient != null) {
|
if (httpClient != null) {
|
||||||
this.httpClient = httpClient;
|
this.httpClient = httpClient;
|
||||||
} else {
|
} else {
|
||||||
this.httpClient = new DefaultHttpClient();
|
this.httpClient = new DefaultHttpClient(configureBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transport != null) {
|
if (transport != null) {
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,6 @@ import io.reactivex.Completable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
|
|
||||||
class WebSocketTransportTest {
|
class WebSocketTransportTest {
|
||||||
// @Test Skipping until we add functional test support
|
|
||||||
public void WebSocketThrowsIfItCantConnect() {
|
|
||||||
Transport transport = new WebSocketTransport(new HashMap<>(), new DefaultHttpClient());
|
|
||||||
RuntimeException exception = assertThrows(RuntimeException.class, () -> transport.start("http://url.fake.example").blockingAwait(1, TimeUnit.SECONDS));
|
|
||||||
assertEquals("There was an error starting the WebSocket transport.", exception.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void CanPassNullExitCodeToOnClosed() {
|
public void CanPassNullExitCodeToOnClosed() {
|
||||||
WebSocketTransport transport = new WebSocketTransport(new HashMap<>(), new WebSocketTestHttpClient());
|
WebSocketTransport transport = new WebSocketTransport(new HashMap<>(), new WebSocketTestHttpClient());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue