Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
16d9115
Initial project structure
javiercn Feb 10, 2021
b7c3420
tmp
javiercn Feb 12, 2021
869718a
tmp
javiercn Feb 22, 2021
4a0705e
tmp
javiercn Feb 23, 2021
2ca6888
Second checkpoint
javiercn Feb 24, 2021
72a1f73
Continue cleanups
javiercn Feb 25, 2021
a5a53dc
Cleanups
javiercn Feb 25, 2021
382dd9a
Make things build
javiercn Feb 25, 2021
3f74734
Move shared files to shared dir
SteveSandersonMS Feb 25, 2021
f03f28b
Minor tidying
SteveSandersonMS Feb 25, 2021
567150a
Refactors based on feedback
javiercn Feb 26, 2021
b843c50
Renames, comments, etc
javiercn Feb 26, 2021
79ba7d3
Get rid of additional projects in favor of unit tests
javiercn Feb 26, 2021
d0ce755
Cleanup and setup tests
javiercn Feb 26, 2021
47a383e
initial unit tests
javiercn Feb 26, 2021
7f0d45c
Try renaming to IpcSender/IpcReceiver
SteveSandersonMS Mar 1, 2021
1273556
IpcSender/IpcReceiver can't be scoped as they must exist before any p…
SteveSandersonMS Mar 1, 2021
d5fcad2
Refactoring to explicit per-page context
SteveSandersonMS Mar 1, 2021
97428ec
Get unit test back
SteveSandersonMS Mar 1, 2021
bb3b3c8
Test for rendering root component
SteveSandersonMS Mar 1, 2021
2619118
Make directory for services
SteveSandersonMS Mar 1, 2021
e35c66b
Add comment
SteveSandersonMS Mar 1, 2021
b3d90aa
Factor out IPC serialization into a common type for reuse in tests
SteveSandersonMS Mar 1, 2021
e14149a
Tidy usings
SteveSandersonMS Mar 1, 2021
3af7f40
Tidy up naming - Initialize -> AttachPage
SteveSandersonMS Mar 1, 2021
06ec16b
Validate that messages are on the expected origin
SteveSandersonMS Mar 1, 2021
faa1398
Typo
SteveSandersonMS Mar 1, 2021
74222c2
Delete redundant project
SteveSandersonMS Mar 1, 2021
42870e7
Rename directory to match repo conventions
SteveSandersonMS Mar 1, 2021
3b65be6
Add projects for Webview2 and WPF
SteveSandersonMS Mar 1, 2021
84bb1d6
Add empty project for WPF sample
SteveSandersonMS Mar 1, 2021
46e25b9
Make WPF sample able to run
SteveSandersonMS Mar 1, 2021
be10765
Reference WebView2 package
SteveSandersonMS Mar 1, 2021
cf9d818
Fix casing in WebView2
SteveSandersonMS Mar 1, 2021
e8d0058
Add WebView to WPF sample
SteveSandersonMS Mar 1, 2021
ea995f0
Supply IServiceProvider to BlazorWebView
SteveSandersonMS Mar 1, 2021
f6ada83
Add some static content
SteveSandersonMS Mar 1, 2021
64051ba
Remove shared WebView2 platform since there's no commonality across W…
SteveSandersonMS Mar 1, 2021
c2d9c93
Begin startup sequence
SteveSandersonMS Mar 1, 2021
d6c575d
Receive web messages
SteveSandersonMS Mar 1, 2021
6b07370
Handle async initialization
SteveSandersonMS Mar 1, 2021
4eb97fe
Supply static content
SteveSandersonMS Mar 1, 2021
8036f1e
Slight tidyup
SteveSandersonMS Mar 1, 2021
74a5160
Add comment
SteveSandersonMS Mar 1, 2021
5432174
Improve WPF control startup
Eilon Mar 2, 2021
4cdd8eb
Exclude WPF-related projects on non-Windows
SteveSandersonMS Mar 2, 2021
e93921e
Fix unit tests
SteveSandersonMS Mar 2, 2021
fd226ee
Begin defining blazor.webview.js
SteveSandersonMS Mar 2, 2021
63589ed
Fix typo
SteveSandersonMS Mar 2, 2021
d39d62b
Supply blazor.webview.js to browser
SteveSandersonMS Mar 2, 2021
d3e9877
Start making blazor.webview.js boot
SteveSandersonMS Mar 2, 2021
29c289f
Add source map for blazor.webview.js
SteveSandersonMS Mar 2, 2021
1cd0e96
Simplify
SteveSandersonMS Mar 2, 2021
b1d6b33
Treat as secure origin to enable more JS APIs
SteveSandersonMS Mar 2, 2021
dd64b44
Begin enabling actual IPC both ways
SteveSandersonMS Mar 2, 2021
df0b52a
Actually renders a component
SteveSandersonMS Mar 2, 2021
27fc955
Basic event dispatching
SteveSandersonMS Mar 2, 2021
2f271c5
Reduce lag
SteveSandersonMS Mar 2, 2021
339dc28
Allow platform to observe startup duration
SteveSandersonMS Mar 2, 2021
faea88f
Move non-WPF specific WebView2 code into common assembly
Eilon Mar 2, 2021
6043ddd
Add some XML docs
SteveSandersonMS Mar 3, 2021
2d47404
Prevent multi-initialization
SteveSandersonMS Mar 3, 2021
cc1984c
Spare platform-specific controls the burden of having to keep track o…
SteveSandersonMS Mar 3, 2021
6759b4c
Fix unit tests
SteveSandersonMS Mar 3, 2021
a9ab01d
Let WPF control specify its own root components via bindable collection
SteveSandersonMS Mar 3, 2021
7f76637
Render an actual .razor component (via compiler workaround)
SteveSandersonMS Mar 3, 2021
794a052
Let the WPF developer specify the host page
SteveSandersonMS Mar 3, 2021
d7df490
Dispose on application exit
SteveSandersonMS Mar 3, 2021
8f2a186
Fix bug
SteveSandersonMS Mar 3, 2021
8088192
Clean up IPC code in TypeScript
SteveSandersonMS Mar 3, 2021
3cdfcfc
Notify about unhandled exceptions
SteveSandersonMS Mar 3, 2021
20d6c7c
Support navigation and JS interop
SteveSandersonMS Mar 3, 2021
ce3bc82
Support reloading when not on the index.html page
SteveSandersonMS Mar 3, 2021
40fb833
Fix filename
Eilon Mar 3, 2021
b817127
Add WinForms BlazorWebView and sample
Eilon Mar 3, 2021
0dc1770
Experiment with tightening the API for adding root components
SteveSandersonMS Mar 4, 2021
0611835
Apply better defaults for desktop apps
SteveSandersonMS Mar 4, 2021
e5dbd56
Don't log a bogus 404 error in the dev tools console
SteveSandersonMS Mar 4, 2021
0a5c425
More build exclusions
SteveSandersonMS Mar 4, 2021
052dbb5
* Implement Dispose pattern in WebViewManager
javiercn Mar 4, 2021
6706656
Fixing another bad Web2View name
Eilon Mar 4, 2021
7a3d593
Make tests compile
Eilon Mar 4, 2021
eff89c8
Add a test
Eilon Mar 4, 2021
f775847
Add public API baselines, cleanup, fix build issues
javiercn Mar 4, 2021
96d27a3
Add license headers
Eilon Mar 4, 2021
5dbcd57
Try to fix CI failure for WebView2Loader during Pack
Eilon Mar 4, 2021
28d9c00
Add missing doc comments
javiercn Mar 4, 2021
ad53fd6
Fix npmproj
javiercn Mar 4, 2021
e127e2f
tmp
javiercn Mar 5, 2021
300a772
Use EmbeddedManifestFileProvider and same Blazor Server MSBuild
javiercn Mar 5, 2021
7a0be28
Add missing doc comments and make them show up as warnings if missing
Eilon Mar 5, 2021
96ec4b4
Update project references
javiercn Mar 5, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 143 additions & 17 deletions AspNetCore.sln

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions eng/Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@
$(RepoRoot)src\Servers\Kestrel\perf\PlatformBenchmarks\**\*.csproj;
$(RepoRoot)src\SignalR\perf\benchmarkapps\**\*.csproj;
" />

<!-- Exclude WinForms and WPF-related projects on non-Windows -->
<ProjectToExclude Condition="'$(TargetOsName)' != 'win'"
Include="
$(RepoRoot)src\Components\WebView\Platforms\WindowsForms\**\*.csproj;
$(RepoRoot)src\Components\WebView\Platforms\Wpf\**\*.csproj;
$(RepoRoot)src\Components\WebView\Samples\BlazorWinFormsApp\**\*.csproj;
$(RepoRoot)src\Components\WebView\Samples\BlazorWpfApp\**\*.csproj;
" />
</ItemGroup>

<Choose>
Expand Down
1 change: 1 addition & 0 deletions eng/Dependencies.props
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ and are generated based on the last package release.
<LatestPackageReference Include="Microsoft.Owin.Security.Cookies" />
<LatestPackageReference Include="Microsoft.Owin.Testing" />
<LatestPackageReference Include="Microsoft.Web.Administration" />
<LatestPackageReference Include="Microsoft.Web.WebView2" />
<LatestPackageReference Include="Microsoft.Web.Xdt" />
<LatestPackageReference Include="NETStandard.Library" />
<LatestPackageReference Include="System.IdentityModel.Tokens.Jwt" />
Expand Down
4 changes: 4 additions & 0 deletions eng/ProjectReferences.props
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@
<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" ProjectPath="$(RepoRoot)src\Components\WebAssembly\WebAssembly\src\Microsoft.AspNetCore.Components.WebAssembly.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebView.WebView2" ProjectPath="$(RepoRoot)src\Components\WebView\Platforms\WebView2\src\Microsoft.AspNetCore.Components.WebView.WebView2.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebView.WindowsForms" ProjectPath="$(RepoRoot)src\Components\WebView\Platforms\WindowsForms\src\Microsoft.AspNetCore.Components.WebView.WindowsForms.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebView.Wpf" ProjectPath="$(RepoRoot)src\Components\WebView\Platforms\Wpf\src\Microsoft.AspNetCore.Components.WebView.Wpf.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.WebView" ProjectPath="$(RepoRoot)src\Components\WebView\WebView\src\Microsoft.AspNetCore.Components.WebView.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Components.Web" ProjectPath="$(RepoRoot)src\Components\Web\src\Microsoft.AspNetCore.Components.Web.csproj" />
<ProjectReferenceProvider Include="Microsoft.Extensions.FileProviders.Embedded" ProjectPath="$(RepoRoot)src\FileProviders\Embedded\src\Microsoft.Extensions.FileProviders.Embedded.csproj" />
<ProjectReferenceProvider Include="Microsoft.Extensions.Configuration.KeyPerFile" ProjectPath="$(RepoRoot)src\Configuration.KeyPerFile\src\Microsoft.Extensions.Configuration.KeyPerFile.csproj" />
Expand Down
1 change: 1 addition & 0 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
<MicrosoftOwinSecurityCookiesVersion>3.0.1</MicrosoftOwinSecurityCookiesVersion>
<MicrosoftOwinTestingVersion>3.0.1</MicrosoftOwinTestingVersion>
<MicrosoftWebAdministrationVersion>11.1.0</MicrosoftWebAdministrationVersion>
<MicrosoftWebWebView2Version>1.0.705.50</MicrosoftWebWebView2Version>
<MicrosoftWebXdtVersion>1.4.0</MicrosoftWebXdtVersion>
<SystemIdentityModelTokensJwtVersion>6.8.0</SystemIdentityModelTokensJwtVersion>
<NuGetVersioningVersion>5.9.0-rc.7121</NuGetVersioningVersion>
Expand Down
7 changes: 7 additions & 0 deletions src/Components/ComponentsNoDeps.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@
"src\\Components\\WebAssembly\\testassets\\Wasm.Authentication.Server\\Wasm.Authentication.Server.csproj",
"src\\Components\\WebAssembly\\testassets\\Wasm.Authentication.Shared\\Wasm.Authentication.Shared.csproj",
"src\\Components\\WebAssembly\\testassets\\WasmLinkerTest\\WasmLinkerTest.csproj",
"src\\Components\\WebView\\Platforms\\WebView2\\src\\Microsoft.AspNetCore.Components.WebView.WebView2.csproj",
"src\\Components\\WebView\\Platforms\\WindowsForms\\src\\Microsoft.AspNetCore.Components.WebView.WindowsForms.csproj",
"src\\Components\\WebView\\Platforms\\Wpf\\src\\Microsoft.AspNetCore.Components.WebView.Wpf.csproj",
"src\\Components\\WebView\\Samples\\BlazorWinFormsApp\\BlazorWinFormsApp.csproj",
"src\\Components\\WebView\\Samples\\BlazorWpfApp\\BlazorWpfApp.csproj",
"src\\Components\\WebView\\WebView\\src\\Microsoft.AspNetCore.Components.WebView.csproj",
"src\\Components\\WebView\\WebView\\test\\Microsoft.AspNetCore.Components.WebView.Test.csproj",
"src\\Components\\Web\\src\\Microsoft.AspNetCore.Components.Web.csproj",
"src\\Components\\Web\\test\\Microsoft.AspNetCore.Components.Web.Tests.csproj",
"src\\Components\\benchmarkapps\\Wasm.Performance\\ConsoleHost\\Wasm.Performance.ConsoleHost.csproj",
Expand Down
4 changes: 2 additions & 2 deletions src/Components/Ignitor/test/Ignitor.Test.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
Expand All @@ -12,7 +12,7 @@
</ItemGroup>

<ItemGroup>
<Compile Include="..\..\Server\src\Circuits\RenderBatchWriter.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\RenderBatchWriter.cs" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,7 @@

<!-- Add a project dependency without reference output assemblies to enforce build order -->
<!-- Applying workaround for https://github.com/microsoft/msbuild/issues/2661 and https://github.com/dotnet/sdk/issues/952 -->
<ProjectReference
Include="..\..\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj"
ReferenceOutputAssemblies="false"
SkipGetTargetFrameworkProperties="true"
UndefineProperties="TargetFramework"
Private="false"
Condition="'$(BuildNodeJS)' != 'false' and '$(BuildingInsideVisualStudio)' != 'true'" />
<ProjectReference Include="..\..\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj" ReferenceOutputAssemblies="false" SkipGetTargetFrameworkProperties="true" UndefineProperties="TargetFramework" Private="false" Condition="'$(BuildNodeJS)' != 'false' and '$(BuildingInsideVisualStudio)' != 'true'" />
</ItemGroup>

<PropertyGroup>
Expand All @@ -47,13 +41,14 @@
<_FileProviderTaskAssembly>$(ArtifactsDir)bin\Microsoft.Extensions.FileProviders.Embedded.Manifest.Task\$(Configuration)\netstandard2.0\Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.dll</_FileProviderTaskAssembly>
</PropertyGroup>

<UsingTask
AssemblyFile="$(_FileProviderTaskAssembly)"
TaskName="Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.GenerateEmbeddedResourcesManifest" />
<UsingTask AssemblyFile="$(_FileProviderTaskAssembly)" TaskName="Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.GenerateEmbeddedResourcesManifest" />

<ItemGroup>
<Compile Include="$(ComponentsSharedSourceRoot)src\CacheHeaderSettings.cs" Link="Shared\CacheHeaderSettings.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\ArrayBuilder.cs" LinkBase="Circuits" />
<Compile Remove="C:\work\AspNetCore4\src\Components\Shared\src\RenderBatchWriter.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\RenderBatchWriter.cs" LinkBase="Circuits" />
<Compile Include="$(ComponentsSharedSourceRoot)src\ArrayBuilderMemoryStream.cs" LinkBase="Circuits" />
<Compile Include="$(ComponentsSharedSourceRoot)src\ElementReferenceJsonConverter.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\ComponentParametersTypeCache.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\RootComponentTypeCache.cs" />
Expand Down Expand Up @@ -96,15 +91,12 @@
<PropertyGroup>
<BlazorServerJSFilename>blazor.server.js</BlazorServerJSFilename>
<!-- Microsoft.AspNetCore.Components.Web.JS.npmproj always capitalizes the directory name. -->
<BlazorServerJSFile
Condition=" '$(Configuration)' == 'Debug' ">..\..\Web.JS\dist\Debug\$(BlazorServerJSFilename)</BlazorServerJSFile>
<BlazorServerJSFile
Condition=" '$(Configuration)' != 'Debug' ">..\..\Web.JS\dist\Release\$(BlazorServerJSFilename)</BlazorServerJSFile>
<BlazorServerJSFile Condition=" '$(Configuration)' == 'Debug' ">..\..\Web.JS\dist\Debug\$(BlazorServerJSFilename)</BlazorServerJSFile>
<BlazorServerJSFile Condition=" '$(Configuration)' != 'Debug' ">..\..\Web.JS\dist\Release\$(BlazorServerJSFilename)</BlazorServerJSFile>
</PropertyGroup>

<!-- blazor.server.js should exist after Microsoft.AspNetCore.Components.Web.JS.npmproj builds. Fall back if not. -->
<Target Name="_CheckBlazorServerJSPath" AfterTargets="ResolveProjectReferences"
Condition=" !EXISTS('$(BlazorServerJSFile)') ">
<Target Name="_CheckBlazorServerJSPath" AfterTargets="ResolveProjectReferences" Condition=" !EXISTS('$(BlazorServerJSFile)') ">
<Warning Text="'$(BlazorServerJSFile)' does not exist. Falling back to checked-in copy." />
<PropertyGroup>
<BlazorServerJSFile>..\..\Web.JS\dist\Release\$(BlazorServerJSFilename)</BlazorServerJSFile>
Expand All @@ -114,8 +106,7 @@
<Target Name="_AddEmbeddedBlazor" AfterTargets="_CheckBlazorServerJSPath">
<ItemGroup>
<EmbeddedResource Include="$(BlazorServerJSFile)" LogicalName="_framework/$(BlazorServerJSFilename)" />
<EmbeddedResource Include="$(BlazorServerJSFile).map" LogicalName="_framework/$(BlazorServerJSFilename).map"
Condition="Exists('$(BlazorServerJSFile).map')" />
<EmbeddedResource Include="$(BlazorServerJSFile).map" LogicalName="_framework/$(BlazorServerJSFilename).map" Condition="Exists('$(BlazorServerJSFile).map')" />
</ItemGroup>
</Target>
</Project>
2 changes: 2 additions & 0 deletions src/Components/Shared/src/ArrayBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#if IGNITOR
namespace Ignitor
#elif BLAZOR_WEBVIEW
namespace Microsoft.AspNetCore.Components.WebView
#elif COMPONENTS_SERVER
namespace Microsoft.AspNetCore.Components.Server.Circuits
#else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.RenderTree;

#if BLAZOR_WEBVIEW
namespace Microsoft.AspNetCore.Components.WebView
#else
namespace Microsoft.AspNetCore.Components.Server.Circuits
#endif
{
/// <summary>
/// Writeable memory stream backed by a an <see cref="ArrayBuilder{T}"/>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

#nullable enable
namespace Microsoft.AspNetCore.Components
{
internal sealed class ElementReferenceJsonConverter : JsonConverter<ElementReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#if IGNITOR
namespace Ignitor
#elif BLAZOR_WEBVIEW
namespace Microsoft.AspNetCore.Components.WebView
#else
namespace Microsoft.AspNetCore.Components.Server.Circuits
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/Components/Shared/src/WebEventData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Text.Json;
using Microsoft.AspNetCore.Components.RenderTree;
using static Microsoft.AspNetCore.Internal.LinkerFlags;

#nullable enable
namespace Microsoft.AspNetCore.Components.Web
{
internal class WebEventData
Expand Down
1 change: 1 addition & 0 deletions src/Components/Web.JS/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules/
dist/Debug/
dist/Release/blazor.webassembly.js
dist/Release/blazor.webview.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
<BuildOutputFiles Condition=" '$(Configuration)' != 'Debug' " Include="dist\Release\blazor.server.js" />
<BuildOutputFiles Condition=" '$(Configuration)' == 'Debug' " Include="dist\Debug\blazor.webassembly.js" />
<BuildOutputFiles Condition=" '$(Configuration)' != 'Debug' " Include="dist\Release\blazor.webassembly.js" />
<BuildOutputFiles Condition=" '$(Configuration)' == 'Debug' " Include="dist\Debug\blazor.webview.js" />
<BuildOutputFiles Condition=" '$(Configuration)' != 'Debug' " Include="dist\Release\blazor.webview.js" />
</ItemGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Components/Web.JS/dist/Release/blazor.webview.js

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions src/Components/Web.JS/src/Boot.WebView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { DotNet } from '@microsoft/dotnet-js-interop';
import { Blazor } from './GlobalExports';
import { shouldAutoStart } from './BootCommon';
import { internalFunctions as navigationManagerFunctions } from './Services/NavigationManager';
import { setEventDispatcher } from './Rendering/Events/EventDispatcher';
import { startIpcReceiver } from './Platform/WebView/WebViewIpcReceiver';
import { sendBrowserEvent, sendAttachPage, sendBeginInvokeDotNetFromJS, sendEndInvokeJSFromDotNet, sendLocationChanged } from './Platform/WebView/WebViewIpcSender';

let started = false;

async function boot(): Promise<void> {
if (started) {
throw new Error('Blazor has already started.');
}
started = true;

startIpcReceiver();

DotNet.attachDispatcher({
beginInvokeDotNetFromJS: sendBeginInvokeDotNetFromJS,
endInvokeJSFromDotNet: sendEndInvokeJSFromDotNet,
});

navigationManagerFunctions.enableNavigationInterception();
navigationManagerFunctions.listenForNavigationEvents(sendLocationChanged);

sendAttachPage(navigationManagerFunctions.getBaseURI(), navigationManagerFunctions.getLocationHref());
}

setEventDispatcher(sendBrowserEvent);

Blazor.start = boot;

if (shouldAutoStart()) {
boot();
}
30 changes: 30 additions & 0 deletions src/Components/Web.JS/src/Platform/WebView/WebViewIpcCommon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const ipcMessagePrefix = '__bwv:';
let applicationIsTerminated = false;

export function trySerializeMessage(messageType: string, args: any[]): string | null {
return applicationIsTerminated
? null
: `${ipcMessagePrefix}${JSON.stringify([messageType, ...args])}`;
}

export function tryDeserializeMessage(message: string): IpcMessage | null {
if (applicationIsTerminated || !message || !message.startsWith(ipcMessagePrefix)) {
return null;
}

const messageAfterPrefix = message.substring(ipcMessagePrefix.length);
const [messageType, ...args] = JSON.parse(messageAfterPrefix);
return { messageType, args };
}

export function setApplicationIsTerminated() {
// If there's an unhandled exception, we'll prevent the webview from doing anything else until
// it reloads the page. This is equivalent to what happens in Blazor Server, and avoids anyone
// taking a dependency on being able to continue interacting after a fatal error.
applicationIsTerminated = true;
}

interface IpcMessage {
messageType: string;
args: any[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { DotNet } from '@microsoft/dotnet-js-interop';
import { showErrorNotification } from '../../BootErrors';
import { OutOfProcessRenderBatch } from '../../Rendering/RenderBatch/OutOfProcessRenderBatch';
import { attachRootComponentToElement, renderBatch } from '../../Rendering/Renderer';
import { setApplicationIsTerminated, tryDeserializeMessage } from './WebViewIpcCommon';
import { sendRenderCompleted } from './WebViewIpcSender';
import { internalFunctions as navigationManagerFunctions } from '../../Services/NavigationManager';

export function startIpcReceiver() {
const messageHandlers = {

'AttachToDocument': (componentId: number, elementSelector: string) => {
attachRootComponentToElement(elementSelector, componentId);
},

'RenderBatch': (batchId: number, batchDataBase64: string) => {
try {
const batchData = base64ToArrayBuffer(batchDataBase64);
renderBatch(0, new OutOfProcessRenderBatch(batchData));
sendRenderCompleted(batchId, null);
} catch (ex) {
sendRenderCompleted(batchId, ex.toString());
}
},

'NotifyUnhandledException': (message: string, stackTrace: string) => {
setApplicationIsTerminated();
console.error(`${message}\n${stackTrace}`);
showErrorNotification();
},

'BeginInvokeJS': DotNet.jsCallDispatcher.beginInvokeJSFromDotNet,

'EndInvokeDotNet': DotNet.jsCallDispatcher.endInvokeDotNetFromJS,

'Navigate': navigationManagerFunctions.navigateTo,
};

(window.external as any).receiveMessage((message: string) => {
const parsedMessage = tryDeserializeMessage(message);
if (parsedMessage) {
if (messageHandlers.hasOwnProperty(parsedMessage.messageType)) {
messageHandlers[parsedMessage.messageType].apply(null, parsedMessage.args);
} else {
throw new Error(`Unsupported IPC message type '${parsedMessage.messageType}'`);
}
}
});
}

// https://stackoverflow.com/a/21797381
// TODO: If the data is large, consider switching over to the native decoder as in https://stackoverflow.com/a/54123275
// But don't force it to be async all the time. Yielding execution leads to perceptible lag.
function base64ToArrayBuffer(base64: string) {
const binaryString = atob(base64);
const length = binaryString.length;
const result = new Uint8Array(length);
for (let i = 0; i < length; i++) {
result[i] = binaryString.charCodeAt(i);
}
return result;
}
34 changes: 34 additions & 0 deletions src/Components/Web.JS/src/Platform/WebView/WebViewIpcSender.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { EventDescriptor } from '../../Rendering/Events/EventDispatcher';
import { trySerializeMessage } from './WebViewIpcCommon';

export function sendAttachPage(baseUrl: string, startUrl: string) {
send('AttachPage', baseUrl, startUrl);
}

export function sendRenderCompleted(batchId: number, errorOrNull: string | null) {
send('OnRenderCompleted', batchId, errorOrNull);
}

export function sendBrowserEvent(descriptor: EventDescriptor, eventArgs: any) {
send('DispatchBrowserEvent', descriptor, eventArgs);
}

export function sendBeginInvokeDotNetFromJS(callId: number, assemblyName: string | null, methodIdentifier: string, dotNetObjectId: number | null, argsJson: string): void {
send('BeginInvokeDotNet', callId ? callId.toString() : null, assemblyName, methodIdentifier, dotNetObjectId || 0, argsJson);
}

export function sendEndInvokeJSFromDotNet(asyncHandle: number, succeeded: boolean, argsJson: any) {
send('EndInvokeJS', asyncHandle, succeeded, argsJson);
}

export function sendLocationChanged(uri: string, intercepted: boolean) {
send('OnLocationChanged', uri, intercepted);
return Promise.resolve(); // Like in Blazor Server, we only issue the notification here - there's no need to wait for a response
}

function send(messageType: string, ...args: any[]) {
const serializedMessage = trySerializeMessage(messageType, args);
if (serializedMessage) {
(window.external as any).sendMessage(serializedMessage);
}
}
Loading