diff --git a/src/Components/Web.JS/@types/dotnet/dotnet.d.ts b/src/Components/Web.JS/@types/dotnet/dotnet.d.ts index 0baceaec3c1a..0e7590eadfdd 100644 --- a/src/Components/Web.JS/@types/dotnet/dotnet.d.ts +++ b/src/Components/Web.JS/@types/dotnet/dotnet.d.ts @@ -3,7 +3,7 @@ //! //! This is generated file, see src/mono/wasm/runtime/rollup.config.js -//! This is not considered public API with backward compatibility guarantees. +//! This is not considered public API with backward compatibility guarantees. declare interface ManagedPointer { __brandManagedPointer: "ManagedPointer"; @@ -43,8 +43,12 @@ declare interface EmscriptenModule { UTF8ArrayToString(u8Array: Uint8Array, idx?: number, maxBytesToRead?: number): string; FS_createPath(parent: string, path: string, canRead?: boolean, canWrite?: boolean): string; FS_createDataFile(parent: string, name: string, data: TypedArray, canRead: boolean, canWrite: boolean, canOwn?: boolean): string; + FS_readFile(filename: string, opts: any): any; removeRunDependency(id: string): void; addRunDependency(id: string): void; + stackSave(): VoidPtr; + stackRestore(stack: VoidPtr): void; + stackAlloc(size: number): VoidPtr; ready: Promise; preInit?: (() => any)[]; preRun?: (() => any)[]; @@ -64,6 +68,11 @@ declare type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Arra * For small numbers of roots, it is preferable to use the mono_wasm_new_root and mono_wasm_new_roots APIs instead. */ declare function mono_wasm_new_root_buffer(capacity: number, name?: string): WasmRootBuffer; +/** + * Allocates a WasmRoot pointing to a root provided and controlled by external code. Typicaly on managed stack. + * Releasing this root will not de-allocate the root space. You still need to call .release(). + */ +declare function mono_wasm_new_external_root(address: VoidPtr | MonoObjectRef): WasmRoot; /** * Allocates temporary storage for a pointer into the managed heap. * Pointers stored here will be visible to the GC, ensuring that the object they point to aren't moved or collected. @@ -71,7 +80,7 @@ declare function mono_wasm_new_root_buffer(capacity: number, name?: string): Was * The result object has get() and set(value) methods, along with a .value property. * When you are done using the root you must call its .release() method. */ -declare function mono_wasm_new_root(value?: T | undefined): WasmRoot; +declare function mono_wasm_new_root(value?: T | undefined): WasmRoot; /** * Releases 1 or more root or root buffer objects. * Multiple objects may be passed on the argument list. @@ -90,26 +99,29 @@ declare class WasmRootBuffer { constructor(offset: VoidPtr, capacity: number, ownsAllocation: boolean, name?: string); _throw_index_out_of_range(): void; _check_in_range(index: number): void; - get_address(index: number): NativePointer; + get_address(index: number): MonoObjectRef; get_address_32(index: number): number; get(index: number): ManagedPointer; set(index: number, value: ManagedPointer): ManagedPointer; + copy_value_from_address(index: number, sourceAddress: MonoObjectRef): void; _unsafe_get(index: number): number; _unsafe_set(index: number, value: ManagedPointer | NativePointer): void; clear(): void; release(): void; toString(): string; } -declare class WasmRoot { - private __buffer; - private __index; - constructor(buffer: WasmRootBuffer, index: number); - get_address(): NativePointer; +interface WasmRoot { + get_address(): MonoObjectRef; get_address_32(): number; + get address(): MonoObjectRef; get(): T; set(value: T): T; get value(): T; set value(value: T); + copy_from_address(source: MonoObjectRef): void; + copy_to_address(destination: MonoObjectRef): void; + copy_from(source: WasmRoot): void; + copy_to(destination: WasmRoot): void; valueOf(): T; clear(): void; release(): void; @@ -125,6 +137,9 @@ interface MonoString extends MonoObject { interface MonoArray extends MonoObject { __brand: "MonoArray"; } +interface MonoObjectRef extends ManagedPointer { + __brandMonoObjectRef: "MonoObjectRef"; +} declare type MonoConfig = { isError: false; assembly_root: string; @@ -141,6 +156,7 @@ declare type MonoConfig = { aot_profiler_options?: AOTProfilerOptions; coverage_profiler_options?: CoverageProfilerOptions; ignore_pdb_load_errors?: boolean; + wait_for_debugger?: number; }; declare type MonoConfigError = { isError: true; @@ -155,6 +171,7 @@ declare type AssetEntry = { culture?: string; load_remote?: boolean; is_optional?: boolean; + buffer?: ArrayBuffer; }; interface AssemblyEntry extends AssetEntry { name: "assembly"; @@ -191,14 +208,18 @@ declare type CoverageProfilerOptions = { write_at?: string; send_to?: string; }; +interface EventPipeSessionOptions { + collectRundownEvents?: boolean; + providers: string; +} declare type DotnetModuleConfig = { disableDotnet6Compatibility?: boolean; config?: MonoConfig | MonoConfigError; configSrc?: string; - scriptDirectory?: string; - onConfigLoaded?: () => void; + onConfigLoaded?: (config: MonoConfig) => Promise; onDotnetReady?: () => void; imports?: DotnetModuleConfigImports; + exports?: string[]; } & Partial; declare type DotnetModuleConfigImports = { require?: (name: string) => any; @@ -222,6 +243,49 @@ declare type DotnetModuleConfigImports = { url?: any; }; +declare type EventPipeSessionID = bigint; +interface EventPipeSession { + get sessionID(): EventPipeSessionID; + start(): void; + stop(): void; + getTraceBlob(): Blob; +} +declare const eventLevel: { + readonly LogAlways: 0; + readonly Critical: 1; + readonly Error: 2; + readonly Warning: 3; + readonly Informational: 4; + readonly Verbose: 5; +}; +declare type EventLevel = typeof eventLevel; +declare type UnnamedProviderConfiguration = Partial<{ + keyword_mask: string | 0; + level: number; + args: string; +}>; +interface ProviderConfiguration extends UnnamedProviderConfiguration { + name: string; +} +declare class SessionOptionsBuilder { + private _rundown?; + private _providers; + constructor(); + static get Empty(): SessionOptionsBuilder; + static get DefaultProviders(): SessionOptionsBuilder; + setRundownEnabled(enabled: boolean): SessionOptionsBuilder; + addProvider(provider: ProviderConfiguration): SessionOptionsBuilder; + addRuntimeProvider(overrideOptions?: UnnamedProviderConfiguration): SessionOptionsBuilder; + addRuntimePrivateProvider(overrideOptions?: UnnamedProviderConfiguration): SessionOptionsBuilder; + addSampleProfilerProvider(overrideOptions?: UnnamedProviderConfiguration): SessionOptionsBuilder; + build(): EventPipeSessionOptions; +} +interface Diagnostics { + EventLevel: EventLevel; + SessionOptionsBuilder: typeof SessionOptionsBuilder; + createEventPipeSession(options?: EventPipeSessionOptions): EventPipeSession | null; +} + declare function mono_wasm_runtime_ready(): void; declare function mono_wasm_setenv(name: string, value: string): void; @@ -238,43 +302,123 @@ declare function mono_wasm_load_config(configFilePath: string): Promise; declare function mono_wasm_load_icu_data(offset: VoidPtr): boolean; +/** + * @deprecated Not GC or thread safe + */ declare function conv_string(mono_obj: MonoString): string | null; +declare function conv_string_root(root: WasmRoot): string | null; +declare function js_string_to_mono_string_root(string: string, result: WasmRoot): void; +/** + * @deprecated Not GC or thread safe + */ declare function js_string_to_mono_string(string: string): MonoString; +/** + * @deprecated Not GC or thread safe. For blazor use only + */ declare function js_to_mono_obj(js_obj: any): MonoObject; +declare function js_to_mono_obj_root(js_obj: any, result: WasmRoot, should_add_in_flight: boolean): void; +declare function js_typed_array_to_array_root(js_obj: any, result: WasmRoot): void; +/** + * @deprecated Not GC or thread safe + */ declare function js_typed_array_to_array(js_obj: any): MonoArray; declare function unbox_mono_obj(mono_obj: MonoObject): any; +declare function unbox_mono_obj_root(root: WasmRoot): any; declare function mono_array_to_js_array(mono_array: MonoArray): any[] | null; +declare function mono_array_root_to_js_array(arrayRoot: WasmRoot): any[] | null; declare function mono_bind_static_method(fqn: string, signature?: string): Function; declare function mono_call_assembly_entry_point(assembly: string, args?: any[], signature?: string): number; declare function mono_wasm_load_bytes_into_heap(bytes: Uint8Array): VoidPtr; -declare type _MemOffset = number | VoidPtr | NativePointer; +declare type _MemOffset = number | VoidPtr | NativePointer | ManagedPointer; +declare type _NumberOrPointer = number | VoidPtr | NativePointer | ManagedPointer; +declare function setB32(offset: _MemOffset, value: number | boolean): void; declare function setU8(offset: _MemOffset, value: number): void; declare function setU16(offset: _MemOffset, value: number): void; -declare function setU32(offset: _MemOffset, value: number): void; +declare function setU32(offset: _MemOffset, value: _NumberOrPointer): void; declare function setI8(offset: _MemOffset, value: number): void; declare function setI16(offset: _MemOffset, value: number): void; declare function setI32(offset: _MemOffset, value: number): void; -declare function setI64(offset: _MemOffset, value: number): void; +/** + * Throws for values which are not 52 bit integer. See Number.isSafeInteger() + */ +declare function setI52(offset: _MemOffset, value: number): void; +/** + * Throws for values which are not 52 bit integer or are negative. See Number.isSafeInteger(). + */ +declare function setU52(offset: _MemOffset, value: number): void; +declare function setI64Big(offset: _MemOffset, value: bigint): void; declare function setF32(offset: _MemOffset, value: number): void; declare function setF64(offset: _MemOffset, value: number): void; +declare function getB32(offset: _MemOffset): boolean; declare function getU8(offset: _MemOffset): number; declare function getU16(offset: _MemOffset): number; declare function getU32(offset: _MemOffset): number; declare function getI8(offset: _MemOffset): number; declare function getI16(offset: _MemOffset): number; declare function getI32(offset: _MemOffset): number; -declare function getI64(offset: _MemOffset): number; +/** + * Throws for Number.MIN_SAFE_INTEGER > value > Number.MAX_SAFE_INTEGER + */ +declare function getI52(offset: _MemOffset): number; +/** + * Throws for 0 > value > Number.MAX_SAFE_INTEGER + */ +declare function getU52(offset: _MemOffset): number; +declare function getI64Big(offset: _MemOffset): bigint; declare function getF32(offset: _MemOffset): number; declare function getF64(offset: _MemOffset): number; declare function mono_run_main_and_exit(main_assembly_name: string, args: string[]): Promise; declare function mono_run_main(main_assembly_name: string, args: string[]): Promise; +interface IDisposable { + dispose(): void; + get isDisposed(): boolean; +} +declare class ManagedObject implements IDisposable { + dispose(): void; + get isDisposed(): boolean; + toString(): string; +} +declare class ManagedError extends Error implements IDisposable { + constructor(message: string); + get stack(): string | undefined; + dispose(): void; + get isDisposed(): boolean; + toString(): string; +} +declare const enum MemoryViewType { + Byte = 0, + Int32 = 1, + Double = 2 +} +interface IMemoryView { + /** + * copies elements from provided source to the wasm memory. + * target has to have the elements of the same type as the underlying C# array. + * same as TypedArray.set() + */ + set(source: TypedArray, targetOffset?: number): void; + /** + * copies elements from wasm memory to provided target. + * target has to have the elements of the same type as the underlying C# array. + */ + copyTo(target: TypedArray, sourceOffset?: number): void; + /** + * same as TypedArray.slice() + */ + slice(start?: number, end?: number): TypedArray; + get length(): number; + get byteLength(): number; +} + +declare function mono_wasm_get_assembly_exports(assembly: string): Promise; + declare const MONO: { mono_wasm_setenv: typeof mono_wasm_setenv; mono_wasm_load_bytes_into_heap: typeof mono_wasm_load_bytes_into_heap; @@ -285,50 +429,97 @@ declare const MONO: { mono_load_runtime_and_bcl_args: typeof mono_load_runtime_and_bcl_args; mono_wasm_new_root_buffer: typeof mono_wasm_new_root_buffer; mono_wasm_new_root: typeof mono_wasm_new_root; + mono_wasm_new_external_root: typeof mono_wasm_new_external_root; mono_wasm_release_roots: typeof mono_wasm_release_roots; mono_run_main: typeof mono_run_main; mono_run_main_and_exit: typeof mono_run_main_and_exit; + mono_wasm_get_assembly_exports: typeof mono_wasm_get_assembly_exports; mono_wasm_add_assembly: (name: string, data: VoidPtr, size: number) => number; mono_wasm_load_runtime: (unused: string, debug_level: number) => void; config: MonoConfig | MonoConfigError; loaded_files: string[]; + setB32: typeof setB32; setI8: typeof setI8; setI16: typeof setI16; setI32: typeof setI32; - setI64: typeof setI64; + setI52: typeof setI52; + setU52: typeof setU52; + setI64Big: typeof setI64Big; setU8: typeof setU8; setU16: typeof setU16; setU32: typeof setU32; setF32: typeof setF32; setF64: typeof setF64; + getB32: typeof getB32; getI8: typeof getI8; getI16: typeof getI16; getI32: typeof getI32; - getI64: typeof getI64; + getI52: typeof getI52; + getU52: typeof getU52; + getI64Big: typeof getI64Big; getU8: typeof getU8; getU16: typeof getU16; getU32: typeof getU32; getF32: typeof getF32; getF64: typeof getF64; + diagnostics: Diagnostics; }; declare type MONOType = typeof MONO; declare const BINDING: { + /** + * @deprecated Not GC or thread safe + */ mono_obj_array_new: (size: number) => MonoArray; + /** + * @deprecated Not GC or thread safe + */ mono_obj_array_set: (array: MonoArray, idx: number, obj: MonoObject) => void; + /** + * @deprecated Not GC or thread safe + */ js_string_to_mono_string: typeof js_string_to_mono_string; + /** + * @deprecated Not GC or thread safe + */ js_typed_array_to_array: typeof js_typed_array_to_array; - js_to_mono_obj: typeof js_to_mono_obj; + /** + * @deprecated Not GC or thread safe + */ mono_array_to_js_array: typeof mono_array_to_js_array; + /** + * @deprecated Not GC or thread safe + */ + js_to_mono_obj: typeof js_to_mono_obj; + /** + * @deprecated Not GC or thread safe + */ conv_string: typeof conv_string; + /** + * @deprecated Not GC or thread safe + */ + unbox_mono_obj: typeof unbox_mono_obj; + /** + * @deprecated Renamed to conv_string_root + */ + conv_string_rooted: typeof conv_string_root; + mono_obj_array_new_ref: (size: number, result: MonoObjectRef) => void; + mono_obj_array_set_ref: (array: MonoObjectRef, idx: number, obj: MonoObjectRef) => void; + js_string_to_mono_string_root: typeof js_string_to_mono_string_root; + js_typed_array_to_array_root: typeof js_typed_array_to_array_root; + js_to_mono_obj_root: typeof js_to_mono_obj_root; + conv_string_root: typeof conv_string_root; + unbox_mono_obj_root: typeof unbox_mono_obj_root; + mono_array_root_to_js_array: typeof mono_array_root_to_js_array; bind_static_method: typeof mono_bind_static_method; call_assembly_entry_point: typeof mono_call_assembly_entry_point; - unbox_mono_obj: typeof unbox_mono_obj; }; declare type BINDINGType = typeof BINDING; interface DotnetPublicAPI { MONO: typeof MONO; BINDING: typeof BINDING; INTERNAL: any; + EXPORTS: any; + IMPORTS: any; Module: EmscriptenModule; RuntimeId: number; RuntimeBuildInfo: { @@ -343,4 +534,33 @@ declare global { function getDotnetRuntime(runtimeId: number): DotnetPublicAPI | undefined; } -export { BINDINGType, CreateDotnetRuntimeType, DotnetModuleConfig, DotnetPublicAPI, EmscriptenModule, MONOType, MonoArray, MonoObject, MonoString, VoidPtr, createDotnetRuntime as default }; +/** + * Span class is JS wrapper for System.Span. This view doesn't own the memory, nor pin the underlying array. + * It's ideal to be used on call from C# with the buffer pinned there or with unmanaged memory. + * It is disposed at the end of the call to JS. + */ +declare class Span implements IMemoryView, IDisposable { + dispose(): void; + get isDisposed(): boolean; + set(source: TypedArray, targetOffset?: number | undefined): void; + copyTo(target: TypedArray, sourceOffset?: number | undefined): void; + slice(start?: number | undefined, end?: number | undefined): TypedArray; + get length(): number; + get byteLength(): number; +} +/** + * ArraySegment class is JS wrapper for System.ArraySegment. + * This wrapper would also pin the underlying array and hold GCHandleType.Pinned until this JS instance is collected. + * User could dispose it manualy. + */ +declare class ArraySegment implements IMemoryView, IDisposable { + dispose(): void; + get isDisposed(): boolean; + set(source: TypedArray, targetOffset?: number | undefined): void; + copyTo(target: TypedArray, sourceOffset?: number | undefined): void; + slice(start?: number | undefined, end?: number | undefined): TypedArray; + get length(): number; + get byteLength(): number; +} + +export { ArraySegment, BINDINGType, CreateDotnetRuntimeType, DotnetModuleConfig, DotnetPublicAPI, EmscriptenModule, IMemoryView, MONOType, ManagedError, ManagedObject, MemoryViewType, MonoArray, MonoObject, MonoString, Span, VoidPtr, createDotnetRuntime as default }; diff --git a/src/Components/Web.JS/src/Boot.WebAssembly.ts b/src/Components/Web.JS/src/Boot.WebAssembly.ts index 0e174cfdd596..41f23688ba96 100644 --- a/src/Components/Web.JS/src/Boot.WebAssembly.ts +++ b/src/Components/Web.JS/src/Boot.WebAssembly.ts @@ -142,6 +142,7 @@ async function boot(options?: Partial): Promise { jsInitializer.invokeAfterStartedCallbacks(Blazor); } +// obsolete, legacy, don't use for new code! function invokeJSFromDotNet(callInfo: Pointer, arg0: any, arg1: any, arg2: any): any { const functionIdentifier = monoPlatform.readStringField(callInfo, 0)!; const resultType = monoPlatform.readInt32Field(callInfo, 4); diff --git a/src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts b/src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts index 0aa9efa09d7e..1cfed154d80a 100644 --- a/src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts +++ b/src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts @@ -18,6 +18,7 @@ import { DotnetPublicAPI, BINDINGType, CreateDotnetRuntimeType, DotnetModuleConf export let BINDING: BINDINGType = undefined as any; export let MONO: MONOType = undefined as any; export let Module: DotnetModuleConfig & EmscriptenModule = undefined as any; +export let IMPORTS: any = undefined as any; const appBinDirName = 'appBinDir'; const uint64HighOrderShift = Math.pow(2, 32); @@ -286,18 +287,19 @@ async function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourc const createDotnetRuntime = await dotnetJsBeingLoaded; await createDotnetRuntime((api) => { - const { MONO: mono, BINDING: binding, Module: module } = api; + const { MONO: mono, BINDING: binding, Module: module, IMPORTS: imports } = api; Module = module; BINDING = binding; MONO = mono; + IMPORTS = imports; // Override the mechanism for fetching the main wasm file so we can connect it to our cache - const instantiateWasm = (imports, successCallback) => { + const instantiateWasm = (wasmImports, successCallback) => { (async () => { let compiledInstance: WebAssembly.Instance; try { const dotnetWasmResource = await wasmBeingLoaded; - compiledInstance = await compileWasmModule(dotnetWasmResource, imports); + compiledInstance = await compileWasmModule(dotnetWasmResource, wasmImports); } catch (ex) { printErr((ex as Error).toString()); throw ex; @@ -329,9 +331,7 @@ async function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourc assembliesBeingLoaded.forEach(r => addResourceAsAssembly(r, changeExtension(r.name, '.dll'))); pdbsBeingLoaded.forEach(r => addResourceAsAssembly(r, r.name)); - Blazor._internal.dotNetCriticalError = (message) => { - printErr(BINDING.conv_string(message) || '(null)'); - }; + Blazor._internal.dotNetCriticalError = (message) => printErr(message || '(null)'); // Wire-up callbacks for satellite assemblies. Blazor will call these as part of the application // startup sequence to load satellite assemblies for the application's culture. @@ -467,6 +467,16 @@ async function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourc // -1 enables debugging with logging disabled. 0 disables debugging entirely. MONO.mono_wasm_load_runtime(appBinDirName, hasDebuggingEnabled() ? -1 : 0); MONO.mono_wasm_runtime_ready(); + try { + BINDING.bind_static_method('invalid-fqn', ''); + } catch (e) { + // HOTFIX: until https://github.com/dotnet/runtime/pull/72275 + // this would always throw, but it will initialize runtime interop as side-effect + } + + // makes Blazor._internal visible to [JSImport] + IMPORTS.Blazor = { _internal: Blazor._internal }; + attachInteropInvoker(); runtimeReadyResolve(api); }; diff --git a/src/Components/WebAssembly/JSInterop/src/WebAssemblyJSObjectReference.cs b/src/Components/WebAssembly/JSInterop/src/WebAssemblyJSObjectReference.cs index ed4f1793e281..1535be93b970 100644 --- a/src/Components/WebAssembly/JSInterop/src/WebAssemblyJSObjectReference.cs +++ b/src/Components/WebAssembly/JSInterop/src/WebAssemblyJSObjectReference.cs @@ -15,6 +15,8 @@ public WebAssemblyJSObjectReference(WebAssemblyJSRuntime jsRuntime, long id) _jsRuntime = jsRuntime; } +#pragma warning disable CS0612 // Type or member is obsolete + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] public TResult InvokeUnmarshalled(string identifier) { ThrowIfDisposed(); @@ -22,6 +24,7 @@ public TResult InvokeUnmarshalled(string identifier) return _jsRuntime.InvokeUnmarshalled(identifier, null, null, null, Id); } + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] public TResult InvokeUnmarshalled(string identifier, T0 arg0) { ThrowIfDisposed(); @@ -29,6 +32,7 @@ public TResult InvokeUnmarshalled(string identifier, T0 arg0) return _jsRuntime.InvokeUnmarshalled(identifier, arg0, null, null, Id); } + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] public TResult InvokeUnmarshalled(string identifier, T0 arg0, T1 arg1) { ThrowIfDisposed(); @@ -36,10 +40,12 @@ public TResult InvokeUnmarshalled(string identifier, T0 arg0, T return _jsRuntime.InvokeUnmarshalled(identifier, arg0, arg1, null, Id); } + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] public TResult InvokeUnmarshalled(string identifier, T0 arg0, T1 arg1, T2 arg2) { ThrowIfDisposed(); return _jsRuntime.InvokeUnmarshalled(identifier, arg0, arg1, arg2, Id); } +#pragma warning restore CS0612 // Type or member is obsolete } diff --git a/src/Components/WebAssembly/JSInterop/src/WebAssemblyJSRuntime.cs b/src/Components/WebAssembly/JSInterop/src/WebAssemblyJSRuntime.cs index 5dba3de28f27..e65fb3e9c20f 100644 --- a/src/Components/WebAssembly/JSInterop/src/WebAssemblyJSRuntime.cs +++ b/src/Components/WebAssembly/JSInterop/src/WebAssemblyJSRuntime.cs @@ -63,16 +63,21 @@ protected override void EndInvokeDotNet(DotNetInvocationInfo callInfo, in DotNet var resultJsonOrErrorMessage = dispatchResult.Success ? dispatchResult.ResultJson! : dispatchResult.Exception!.ToString(); +#pragma warning disable CS0618 // Type or member is obsolete InvokeUnmarshalled("Blazor._internal.endInvokeDotNetFromJS", callInfo.CallId, dispatchResult.Success, resultJsonOrErrorMessage); +#pragma warning restore CS0618 // Type or member is obsolete } /// protected override void SendByteArray(int id, byte[] data) { +#pragma warning disable CS0618 // Type or member is obsolete InvokeUnmarshalled("Blazor._internal.receiveByteArray", id, data); +#pragma warning restore CS0618 // Type or member is obsolete } + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] internal TResult InvokeUnmarshalled(string identifier, T0 arg0, T1 arg1, T2 arg2, long targetInstanceId) { var resultType = JSCallResultTypeHelper.FromGeneric(); @@ -122,18 +127,22 @@ private IJSStreamReference DeserializeJSStreamReference(string serializedStreamR } /// + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] public TResult InvokeUnmarshalled(string identifier) => InvokeUnmarshalled(identifier, null, null, null, 0); /// + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] public TResult InvokeUnmarshalled(string identifier, T0 arg0) => InvokeUnmarshalled(identifier, arg0, null, null, 0); /// + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] public TResult InvokeUnmarshalled(string identifier, T0 arg0, T1 arg1) => InvokeUnmarshalled(identifier, arg0, arg1, null, 0); /// + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] public TResult InvokeUnmarshalled(string identifier, T0 arg0, T1 arg1, T2 arg2) => InvokeUnmarshalled(identifier, arg0, arg1, arg2, 0); } diff --git a/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyCultureProvider.cs b/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyCultureProvider.cs index bf776eb5cb68..331cbb8e7ab6 100644 --- a/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyCultureProvider.cs +++ b/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyCultureProvider.cs @@ -74,6 +74,7 @@ public virtual async ValueTask LoadCurrentCultureResourcesAsync() // assemblies. We effectively want to resovle a Task but there is no way to express this // using interop. We'll instead do this in two parts: // getSatelliteAssemblies resolves when all satellite assemblies to be loaded in .NET are fetched and available in memory. +#pragma warning disable CS0618 // Type or member is obsolete var count = (int)await _invoker.InvokeUnmarshalled>( GetSatelliteAssemblies, culturesToLoad.ToArray(), @@ -91,6 +92,7 @@ public virtual async ValueTask LoadCurrentCultureResourcesAsync() null, null, null); +#pragma warning restore CS0618 // Type or member is obsolete for (var i = 0; i < assemblies.Length; i++) { diff --git a/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHostBuilder.cs b/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHostBuilder.cs index dca7d0a70990..6bceb9f33011 100644 --- a/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHostBuilder.cs +++ b/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHostBuilder.cs @@ -90,6 +90,7 @@ internal WebAssemblyHostBuilder(IJSUnmarshalledRuntime jsRuntime, JsonSerializer [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "Root components are expected to be defined in assemblies that do not get trimmed.")] private void InitializeRegisteredRootComponents(IJSUnmarshalledRuntime jsRuntime) { +#pragma warning disable CS0618 // Type or member is obsolete var componentsCount = jsRuntime.InvokeUnmarshalled(RegisteredComponentsInterop.GetRegisteredComponentsCount); if (componentsCount == 0) { @@ -106,6 +107,7 @@ private void InitializeRegisteredRootComponents(IJSUnmarshalledRuntime jsRuntime var serializedParameterValues = jsRuntime.InvokeUnmarshalled(RegisteredComponentsInterop.GetParameterValues, id, null, null); registeredComponents[i] = new WebAssemblyComponentMarker(WebAssemblyComponentMarker.ClientMarkerType, assembly, typeName, serializedParameterDefinitions, serializedParameterValues, id.ToString(CultureInfo.InvariantCulture)); } +#pragma warning restore CS0618 // Type or member is obsolete var componentDeserializer = WebAssemblyComponentParameterDeserializer.Instance; foreach (var registeredComponent in registeredComponents) @@ -129,20 +131,26 @@ private void InitializeRegisteredRootComponents(IJSUnmarshalledRuntime jsRuntime private void InitializePersistedState(IJSUnmarshalledRuntime jsRuntime) { +#pragma warning disable CS0618 // Type or member is obsolete _persistedState = jsRuntime.InvokeUnmarshalled("Blazor._internal.getPersistedState"); +#pragma warning restore CS0618 // Type or member is obsolete } private static void InitializeNavigationManager(IJSUnmarshalledRuntime jsRuntime) { +#pragma warning disable CS0618 // Type or member is obsolete var baseUri = jsRuntime.InvokeUnmarshalled(BrowserNavigationManagerInterop.GetBaseUri); var uri = jsRuntime.InvokeUnmarshalled(BrowserNavigationManagerInterop.GetLocationHref); +#pragma warning restore CS0618 // Type or member is obsolete WebAssemblyNavigationManager.Instance = new WebAssemblyNavigationManager(baseUri, uri); } private WebAssemblyHostEnvironment InitializeEnvironment(IJSUnmarshalledRuntime jsRuntime) { +#pragma warning disable CS0618 // Type or member is obsolete var applicationEnvironment = jsRuntime.InvokeUnmarshalled("Blazor._internal.getApplicationEnvironment"); +#pragma warning restore CS0618 // Type or member is obsolete var hostEnvironment = new WebAssemblyHostEnvironment(applicationEnvironment, WebAssemblyNavigationManager.Instance.BaseUri); Services.AddSingleton(hostEnvironment); @@ -155,8 +163,10 @@ private WebAssemblyHostEnvironment InitializeEnvironment(IJSUnmarshalledRuntime foreach (var configFile in configFiles) { +#pragma warning disable CS0618 // Type or member is obsolete var appSettingsJson = jsRuntime.InvokeUnmarshalled( "Blazor._internal.getConfig", configFile); +#pragma warning restore CS0618 // Type or member is obsolete if (appSettingsJson != null) { diff --git a/src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs b/src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs index 7b8a0ba03b25..3ea5c30f6929 100644 --- a/src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs +++ b/src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs @@ -35,7 +35,9 @@ internal static async Task InitializeAsync() // See https://github.com/dotnet/aspnetcore/issues/37357#issuecomment-941237000 var jsObjectReference = (IJSUnmarshalledObjectReference)(await DefaultWebAssemblyJSRuntime.Instance.InvokeAsync("import", "/_framework/blazor-hotreload.js")); +#pragma warning disable CS0618 // Type or member is obsolete await jsObjectReference.InvokeUnmarshalled>("receiveHotReload"); +#pragma warning restore CS0618 // Type or member is obsolete } } diff --git a/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj b/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj index f0652aab5814..411872891e08 100644 --- a/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj +++ b/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj @@ -9,6 +9,7 @@ true enable true + true diff --git a/src/Components/WebAssembly/WebAssembly/src/Rendering/WebAssemblyRenderer.cs b/src/Components/WebAssembly/WebAssembly/src/Rendering/WebAssemblyRenderer.cs index bc88c33d6d4b..0481c89aadb8 100644 --- a/src/Components/WebAssembly/WebAssembly/src/Rendering/WebAssemblyRenderer.cs +++ b/src/Components/WebAssembly/WebAssembly/src/Rendering/WebAssemblyRenderer.cs @@ -83,10 +83,12 @@ protected override void ProcessPendingRender() /// protected override Task UpdateDisplayAsync(in RenderBatch batch) { +#pragma warning disable CS0618 // Type or member is obsolete DefaultWebAssemblyJSRuntime.Instance.InvokeUnmarshalled( "Blazor._internal.renderBatch", RendererId, batch); +#pragma warning restore CS0618 // Type or member is obsolete if (WebAssemblyCallQueue.HasUnstartedWork) { diff --git a/src/Components/WebAssembly/WebAssembly/src/Services/DefaultWebAssemblyJSRuntime.cs b/src/Components/WebAssembly/WebAssembly/src/Services/DefaultWebAssemblyJSRuntime.cs index f544f4a8568c..16ec802fbc36 100644 --- a/src/Components/WebAssembly/WebAssembly/src/Services/DefaultWebAssemblyJSRuntime.cs +++ b/src/Components/WebAssembly/WebAssembly/src/Services/DefaultWebAssemblyJSRuntime.cs @@ -86,7 +86,9 @@ public static void BeginInvokeDotNet(string callId, string assemblyNameOrDotNetO /// Id of the byte array public static void NotifyByteArrayAvailable(int id) { +#pragma warning disable CS0618 // Type or member is obsolete var data = Instance.InvokeUnmarshalled("Blazor._internal.retrieveByteArray"); +#pragma warning restore CS0618 // Type or member is obsolete DotNetDispatcher.ReceiveByteArray(Instance, id, data); } diff --git a/src/Components/WebAssembly/WebAssembly/src/Services/LazyAssemblyLoader.cs b/src/Components/WebAssembly/WebAssembly/src/Services/LazyAssemblyLoader.cs index 69ea6388bb6e..e739793b9edf 100644 --- a/src/Components/WebAssembly/WebAssembly/src/Services/LazyAssemblyLoader.cs +++ b/src/Components/WebAssembly/WebAssembly/src/Services/LazyAssemblyLoader.cs @@ -105,9 +105,11 @@ private async Task> LoadAssembliesInClientAsync(IEnumerabl } var jsRuntime = (IJSUnmarshalledRuntime)_jsRuntime; +#pragma warning disable CS0618 // Type or member is obsolete var count = (int)await jsRuntime.InvokeUnmarshalled>( GetLazyAssemblies, newAssembliesToLoad.ToArray()); +#pragma warning restore CS0618 // Type or member is obsolete if (count == 0) { @@ -115,8 +117,10 @@ private async Task> LoadAssembliesInClientAsync(IEnumerabl } var loadedAssemblies = new List(); +#pragma warning disable CS0618 // Type or member is obsolete var assemblies = jsRuntime.InvokeUnmarshalled(ReadLazyAssemblies); var pdbs = jsRuntime.InvokeUnmarshalled(ReadLazyPDBs); +#pragma warning restore CS0618 // Type or member is obsolete for (int i = 0; i < assemblies.Length; i++) { diff --git a/src/Components/WebAssembly/WebAssembly/src/Services/WebAssemblyConsoleLogger.cs b/src/Components/WebAssembly/WebAssembly/src/Services/WebAssemblyConsoleLogger.cs index 9467cd8335ba..c5a658be60cf 100644 --- a/src/Components/WebAssembly/WebAssembly/src/Services/WebAssemblyConsoleLogger.cs +++ b/src/Components/WebAssembly/WebAssembly/src/Services/WebAssemblyConsoleLogger.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Runtime.InteropServices.JavaScript; using System.Text; using Microsoft.Extensions.Logging; using Microsoft.JSInterop; @@ -79,19 +80,19 @@ private void WriteMessage(LogLevel logLevel, string logName, int eventId, string // messages if you enable "Verbose" in the filter dropdown (which is off // by default). As such "console.debug" is the best choice for messages // with a lower severity level than "Information". - _jsRuntime.InvokeVoid("console.debug", formattedMessage); + ConsoleLoggerInterop.ConsoleDebug(formattedMessage); break; case LogLevel.Information: - _jsRuntime.InvokeVoid("console.info", formattedMessage); + ConsoleLoggerInterop.ConsoleInfo(formattedMessage); break; case LogLevel.Warning: - _jsRuntime.InvokeVoid("console.warn", formattedMessage); + ConsoleLoggerInterop.ConsoleWarn(formattedMessage); break; case LogLevel.Error: - _jsRuntime.InvokeVoid("console.error", formattedMessage); + ConsoleLoggerInterop.ConsoleError(formattedMessage); break; case LogLevel.Critical: - _jsRuntime.InvokeUnmarshalled("Blazor._internal.dotNetCriticalError", formattedMessage); + ConsoleLoggerInterop.DotNetCriticalError(formattedMessage); break; default: // invalid enum values Debug.Assert(logLevel != LogLevel.None, "This method is never called with LogLevel.None."); @@ -165,3 +166,17 @@ private sealed class NoOpDisposable : IDisposable public void Dispose() { } } } + +internal static partial class ConsoleLoggerInterop +{ + [JSImport("globalThis.console.debug")] + public static partial void ConsoleDebug(string message); + [JSImport("globalThis.console.info")] + public static partial void ConsoleInfo(string message); + [JSImport("globalThis.console.warn")] + public static partial void ConsoleWarn(string message); + [JSImport("globalThis.console.error")] + public static partial void ConsoleError(string message); + [JSImport("Blazor._internal.dotNetCriticalError")] + public static partial void DotNetCriticalError(string message); +} diff --git a/src/Components/WebAssembly/WebAssembly/test/Hosting/WebAssemblyCultureProviderTest.cs b/src/Components/WebAssembly/WebAssembly/test/Hosting/WebAssemblyCultureProviderTest.cs index 4239f3ad59eb..9f182ef17a1b 100644 --- a/src/Components/WebAssembly/WebAssembly/test/Hosting/WebAssemblyCultureProviderTest.cs +++ b/src/Components/WebAssembly/WebAssembly/test/Hosting/WebAssemblyCultureProviderTest.cs @@ -33,6 +33,7 @@ public async Task LoadCurrentCultureResourcesAsync_ReadsAssemblies() // Arrange using var cultureReplacer = new CultureReplacer("en-GB"); var invoker = new Mock(); +#pragma warning disable CS0618 // Type or member is obsolete invoker.Setup(i => i.InvokeUnmarshalled>(GetSatelliteAssemblies, new[] { "en-GB", "en" }, null, null)) .Returns(Task.FromResult(1)) .Verifiable(); @@ -40,6 +41,7 @@ public async Task LoadCurrentCultureResourcesAsync_ReadsAssemblies() invoker.Setup(i => i.InvokeUnmarshalled(ReadSatelliteAssemblies, null, null, null)) .Returns(new object[] { File.ReadAllBytes(GetType().Assembly.Location) }) .Verifiable(); +#pragma warning restore CS0618 // Type or member is obsolete var loader = new WebAssemblyCultureProvider(invoker.Object, CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture); @@ -56,17 +58,21 @@ public async Task LoadCurrentCultureResourcesAsync_DoesNotReadAssembliesWhenTher // Arrange using var cultureReplacer = new CultureReplacer("en-GB"); var invoker = new Mock(); +#pragma warning disable CS0618 // Type or member is obsolete invoker.Setup(i => i.InvokeUnmarshalled>(GetSatelliteAssemblies, new[] { "en-GB", "en" }, null, null)) .Returns(Task.FromResult(0)) .Verifiable(); +#pragma warning restore CS0618 // Type or member is obsolete var loader = new WebAssemblyCultureProvider(invoker.Object, CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture); // Act await loader.LoadCurrentCultureResourcesAsync(); +#pragma warning disable CS0618 // Type or member is obsolete // Assert invoker.Verify(i => i.InvokeUnmarshalled(ReadSatelliteAssemblies, null, null, null), Times.Never()); +#pragma warning restore CS0618 // Type or member is obsolete } [Fact] diff --git a/src/Components/test/testassets/BasicTestApp/InteropComponent.razor b/src/Components/test/testassets/BasicTestApp/InteropComponent.razor index f34ae1dce004..fd496a8cd1b5 100644 --- a/src/Components/test/testassets/BasicTestApp/InteropComponent.razor +++ b/src/Components/test/testassets/BasicTestApp/InteropComponent.razor @@ -401,6 +401,7 @@ // we should be able to downcast a IJSInProcessObjectReference as a IJSUnmarshalledObjectReference var unmarshalledCast = (IJSUnmarshalledObjectReference)jsInProcObjectReference; +#pragma warning disable CS0618 // Type or member is obsolete ReturnValues["jsCastedUnmarshalledObjectReference.unmarshalledFunction"] = unmarshalledCast.InvokeUnmarshalled("unmarshalledFunction", new InteropStruct { Message = "Sent from .NET", @@ -418,6 +419,7 @@ var dataReference = unmarshalledRuntime.InvokeUnmarshalled("jsToDotNetStreamReturnValue"); +#pragma warning restore CS0618 // Type or member is obsolete using var dataReferenceStream = await dataReference.OpenReadStreamAsync(); await ValidateStreamValuesAsync("jsToDotNetStreamReturnValueUnmarshalled", dataReferenceStream); } diff --git a/src/JSInterop/Microsoft.JSInterop/src/IJSUnmarshalledObjectReference.cs b/src/JSInterop/Microsoft.JSInterop/src/IJSUnmarshalledObjectReference.cs index faff2634c47e..e906556b0013 100644 --- a/src/JSInterop/Microsoft.JSInterop/src/IJSUnmarshalledObjectReference.cs +++ b/src/JSInterop/Microsoft.JSInterop/src/IJSUnmarshalledObjectReference.cs @@ -14,6 +14,7 @@ public interface IJSUnmarshalledObjectReference : IJSInProcessObjectReference /// The .NET type corresponding to the function's return value type. /// The identifier used when registering the target function. /// The result of the function invocation. + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] TResult InvokeUnmarshalled(string identifier); /// @@ -24,6 +25,7 @@ public interface IJSUnmarshalledObjectReference : IJSInProcessObjectReference /// The identifier used when registering the target function. /// The first argument. /// The result of the function invocation. + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] TResult InvokeUnmarshalled(string identifier, T0 arg0); /// @@ -36,6 +38,7 @@ public interface IJSUnmarshalledObjectReference : IJSInProcessObjectReference /// The first argument. /// The second argument. /// The result of the function invocation. + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] TResult InvokeUnmarshalled(string identifier, T0 arg0, T1 arg1); /// @@ -50,5 +53,6 @@ public interface IJSUnmarshalledObjectReference : IJSInProcessObjectReference /// The second argument. /// The third argument. /// The result of the function invocation. + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] TResult InvokeUnmarshalled(string identifier, T0 arg0, T1 arg1, T2 arg2); } diff --git a/src/JSInterop/Microsoft.JSInterop/src/IJSUnmarshalledRuntime.cs b/src/JSInterop/Microsoft.JSInterop/src/IJSUnmarshalledRuntime.cs index 1708130ad5a1..d5241f139258 100644 --- a/src/JSInterop/Microsoft.JSInterop/src/IJSUnmarshalledRuntime.cs +++ b/src/JSInterop/Microsoft.JSInterop/src/IJSUnmarshalledRuntime.cs @@ -17,6 +17,7 @@ public interface IJSUnmarshalledRuntime /// The .NET type corresponding to the function's return value type. /// The identifier used when registering the target function. /// The result of the function invocation. + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] TResult InvokeUnmarshalled(string identifier); /// @@ -27,6 +28,7 @@ public interface IJSUnmarshalledRuntime /// The identifier used when registering the target function. /// The first argument. /// The result of the function invocation. + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] TResult InvokeUnmarshalled(string identifier, T0 arg0); /// @@ -39,6 +41,7 @@ public interface IJSUnmarshalledRuntime /// The first argument. /// The second argument. /// The result of the function invocation. + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] TResult InvokeUnmarshalled(string identifier, T0 arg0, T1 arg1); /// @@ -53,5 +56,6 @@ public interface IJSUnmarshalledRuntime /// The second argument. /// The third argument. /// The result of the function invocation. + [Obsolete("This method is obsolete. Use JSImportAttribute instead.")] TResult InvokeUnmarshalled(string identifier, T0 arg0, T1 arg1, T2 arg2); }