Skip to content

[Blazor] Public API for interacting with runtime #49420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/Components/Web.JS/@types/dotnet/dotnet.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,4 +432,4 @@ declare global {
}
declare const createDotnetRuntime: CreateDotnetRuntimeType;

export { AssetEntry, CreateDotnetRuntimeType, DotnetModuleConfig, EmscriptenModule, GlobalizationMode, IMemoryView, ModuleAPI, MonoConfig, ResourceRequest, RuntimeAPI, createDotnetRuntime as default, dotnet, exit };
export { AssetEntry, CreateDotnetRuntimeType, DotnetHostBuilder, DotnetModuleConfig, EmscriptenModule, GlobalizationMode, IMemoryView, ModuleAPI, MonoConfig, ResourceRequest, RuntimeAPI, createDotnetRuntime as default, dotnet, exit };
3 changes: 3 additions & 0 deletions src/Components/Web.JS/src/GlobalExports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { getNextChunk } from './StreamingInterop';
import { RootComponentsFunctions } from './Rendering/JSRootComponents';
import { attachWebRendererInterop } from './Rendering/WebRendererInteropMethods';
import { WebStartOptions } from './Platform/WebStartOptions';
import { RuntimeAPI } from 'dotnet';

// TODO: It's kind of hard to tell which .NET platform(s) some of these APIs are relevant to.
// It's important to know this information when dealing with the possibility of mulitple .NET platforms being available.
Expand All @@ -38,6 +39,7 @@ interface IBlazor {
start?: ((userOptions?: Partial<CircuitStartOptions>) => Promise<void>) | ((options?: Partial<WebAssemblyStartOptions>) => Promise<void>) | ((options?: Partial<WebStartOptions>) => Promise<void>);
platform?: Platform;
rootComponents: typeof RootComponentsFunctions;
runtime: RuntimeAPI,

_internal: {
navigationManager: typeof navigationManagerInternalFunctions | any;
Expand Down Expand Up @@ -91,6 +93,7 @@ export const Blazor: IBlazor = {
navigateTo,
registerCustomEventType,
rootComponents: RootComponentsFunctions,
runtime: {} as RuntimeAPI,

_internal: {
navigationManager: navigationManagerInternalFunctions,
Expand Down
19 changes: 18 additions & 1 deletion src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,25 @@ function prepareRuntimeConfig(options: Partial<WebAssemblyStartOptions>): Dotnet
async function createRuntimeInstance(options: Partial<WebAssemblyStartOptions>): Promise<PlatformApi> {
const { dotnet } = await importDotnetJs(options);
const moduleConfig = prepareRuntimeConfig(options);

if (options.applicationCulture) {
dotnet.withApplicationCulture(options.applicationCulture);
}

if (options.environment) {
dotnet.withApplicationEnvironment(options.environment);
}

if (options.loadBootResource) {
dotnet.withResourceLoader(options.loadBootResource);
}

const anyDotnet = (dotnet as any);
anyDotnet.withModuleConfig(moduleConfig);

anyDotnet.withStartupOptions(options).withModuleConfig(moduleConfig);
if (options.configureRuntime) {
options.configureRuntime(dotnet);
}

runtime = await dotnet.create();
const { MONO: mono, BINDING: binding, Module: module, setModuleImports, INTERNAL: mono_internal, getConfig, invokeLibraryInitializers } = runtime;
Expand All @@ -223,6 +239,7 @@ async function createRuntimeInstance(options: Partial<WebAssemblyStartOptions>):

attachDebuggerHotkey(getConfig());

Blazor.runtime = runtime;
Blazor._internal.dotNetCriticalError = printErr;
setModuleImports('blazor-internal', {
Blazor: { _internal: Blazor._internal },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import { DotnetHostBuilder } from 'dotnet';

export interface WebAssemblyStartOptions {
/**
* Overrides the built-in boot resource loading mechanism so that boot resources can be fetched
Expand All @@ -11,7 +13,7 @@ export interface WebAssemblyStartOptions {
* @param integrity The integrity string representing the expected content in the response.
* @returns A URI string or a Response promise to override the loading process, or null/undefined to allow the default loading behavior.
*/
loadBootResource(type: WebAssemblyBootResourceType, name: string, defaultUri: string, integrity: string) : string | Promise<Response> | null | undefined;
loadBootResource(type: WebAssemblyBootResourceType, name: string, defaultUri: string, integrity: string): string | Promise<Response> | null | undefined;

/**
* Override built-in environment setting on start.
Expand All @@ -22,6 +24,11 @@ export interface WebAssemblyStartOptions {
* Gets the application culture. This is a name specified in the BCP 47 format. See https://tools.ietf.org/html/bcp47
*/
applicationCulture?: string;

/**
* Allows to override .NET runtime configuration.
*/
configureRuntime(builder: DotnetHostBuilder): void;
}

// This type doesn't have to align with anything in BootConfig.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using BasicTestApp;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.E2ETesting;
using OpenQA.Selenium;
using Xunit.Abstractions;

namespace Microsoft.AspNetCore.Components.E2ETest.Tests;

public class WebAssemblyConfigureRuntimeTest : ServerTestBase<BlazorWasmTestAppFixture<BasicTestApp.Program>>
{
public WebAssemblyConfigureRuntimeTest(
BrowserFixture browserFixture,
BlazorWasmTestAppFixture<Program> serverFixture,
ITestOutputHelper output)
: base(browserFixture, serverFixture, output)
{
_serverFixture.PathBase = "/subdir";
}

protected override void InitializeAsyncCore()
{
base.InitializeAsyncCore();

Navigate(ServerPathBase, noReload: false);
Browser.MountTestComponent<ConfigureRuntime>();
}

[Fact]
public void ConfigureRuntimeWorks()
{
var element = Browser.Exists(By.Id("environment"));
Browser.Equal("true", () => element.Text);
}

[Fact]
public void BlazorRuntimeApiWorks()
{
var element = Browser.Exists(By.Id("build-configuration"));
Browser.Equal("Release", () => element.Text);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@using Microsoft.JSInterop
@inject IJSRuntime JsRuntime

<p>
Environment variable CONFIGURE_RUNTIME: <span id="environment">@Environment.GetEnvironmentVariable("CONFIGURE_RUNTIME")</span>
</p>
<p>
.NET runtime build configuration: <span id="build-configuration">@RuntimeBuildConfiguration</span>
</p>

@code
{
protected string RuntimeBuildConfiguration { get; set; }

protected override async Task OnInitializedAsync()
{
RuntimeBuildConfiguration = await JsRuntime.InvokeAsync<string>("window.getRuntimeBuildConfiguration");
}
}
1 change: 1 addition & 0 deletions src/Components/test/testassets/BasicTestApp/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<option value="BasicTestApp.ComponentRefComponent">Component ref component</option>
<option value="BasicTestApp.ConcurrentRenderParent">Concurrent rendering</option>
<option value="BasicTestApp.ConfigurationComponent">Configuration</option>
<option value="BasicTestApp.ConfigureRuntime">Configure runtime</option>
<option value="BasicTestApp.ContentEditable">Content-editable</option>
<option value="BasicTestApp.CounterComponent">Counter</option>
<option value="BasicTestApp.CounterComponentUsingChild">Counter using child component</option>
Expand Down
16 changes: 15 additions & 1 deletion src/Components/test/testassets/BasicTestApp/wwwroot/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,22 @@
function getCurrentUrl() {
return location.href;
}

function getRuntimeBuildConfiguration() {
return Blazor.runtime.runtimeBuildInfo.buildConfiguration;
}
</script>
<script src="_framework/blazor.webassembly.js" autostart="false"></script>

<script>
(function(){
Blazor.start({
configureRuntime: dotnet => {
dotnet.withEnvironmentVariable("CONFIGURE_RUNTIME", "true");
}
});
})();
</script>
<script src="_framework/blazor.webassembly.js"></script>

<!-- Used by ExternalContentPackage -->
<script src="_content/TestContentPackage/prompt.js"></script>
Expand Down