Skip to content

Commit 7247e11

Browse files
authored
Expose BlazorWebView.TryDispatchAsync() API for access to scoped services (#13425)
This makes the new WebViewManager.TryDispatchAsync() API available to users of BlazorWebView.
1 parent 523e555 commit 7247e11

24 files changed

+556
-239
lines changed

src/BlazorWebView/samples/BlazorWinFormsApp/Form1.cs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Windows.Forms;
6+
using Microsoft.AspNetCore.Components;
67
using Microsoft.AspNetCore.Components.Web;
78
using Microsoft.AspNetCore.Components.WebView.WindowsForms;
89
using Microsoft.Extensions.DependencyInjection;
@@ -14,6 +15,12 @@ namespace BlazorWinFormsApp
1415
public partial class Form1 : Form
1516
{
1617
private readonly AppState _appState = new();
18+
private const bool ValidateDIScopes =
19+
#if DEBUG
20+
true;
21+
#else
22+
false;
23+
#endif
1724

1825
public Form1()
1926
{
@@ -29,6 +36,7 @@ public Form1()
2936
services1.AddBlazorWebViewDeveloperTools();
3037
#endif
3138
services1.AddSingleton<AppState>(_appState);
39+
services1.AddScoped<ExampleJsInterop>();
3240

3341
var services2 = new ServiceCollection();
3442
services2.AddWindowsFormsBlazorWebView();
@@ -41,12 +49,12 @@ public Form1()
4149
InitializeComponent();
4250

4351
blazorWebView1.HostPage = @"wwwroot\index.html";
44-
blazorWebView1.Services = services1.BuildServiceProvider();
52+
blazorWebView1.Services = services1.BuildServiceProvider(validateScopes: ValidateDIScopes);
4553
blazorWebView1.RootComponents.Add<Main>("#app");
4654
blazorWebView1.RootComponents.RegisterForJavaScript<MyDynamicComponent>("my-dynamic-root-component");
4755

4856
customFilesBlazorWebView.HostPage = @"wwwroot\customindex.html";
49-
customFilesBlazorWebView.Services = services2.BuildServiceProvider();
57+
customFilesBlazorWebView.Services = services2.BuildServiceProvider(validateScopes: ValidateDIScopes);
5058
customFilesBlazorWebView.RootComponents.Add<Main>("#app");
5159
}
5260

@@ -77,5 +85,23 @@ private void sendScriptalertToolStripMenuItem_Click(object sender, EventArgs e)
7785
{
7886
blazorWebView1.WebView.CoreWebView2.ExecuteScriptAsync("alert('hello from a native menu')");
7987
}
88+
89+
private async void _useServicesButton_Click(object sender, EventArgs e)
90+
{
91+
// Call DispatchAsync() to use scoped services in the context of the BlazorWebView
92+
var called = await blazorWebView1.TryDispatchAsync(async (services) =>
93+
{
94+
var exampleJsInterop = services.GetRequiredService<ExampleJsInterop>();
95+
var promptResponse = await exampleJsInterop.Prompt("Enter your name");
96+
97+
var navMan = services.GetRequiredService<NavigationManager>();
98+
navMan.NavigateTo($"/other/{promptResponse}");
99+
});
100+
101+
if (!called)
102+
{
103+
MessageBox.Show(this, "Couldn't call TryDispatchAsync!");
104+
}
105+
}
80106
}
81107
}

src/BlazorWebView/samples/BlazorWinFormsApp/Form1.designer.cs

Lines changed: 232 additions & 228 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/BlazorWebView/samples/BlazorWinFormsApp/Pages/Other.razor

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
@page "/other"
1+
@page "/other/{name?}"
22
@inject NavigationManager NavigationManager
33

44
<div>
55
Here is another page. Looks like navigation works.
66

7+
@if (!string.IsNullOrEmpty(Name))
8+
{
9+
<div>I even found your name: @Name</div>
10+
}
11+
712
<button @onclick="BackToHome">Navigate back programmatically</button>
813
</div>
914

@@ -17,6 +22,8 @@
1722
</div>
1823

1924
@code {
25+
[Parameter] public string Name { get; set; }
26+
2027
string textValue;
2128

2229
void BackToHome()

src/BlazorWebView/samples/WebViewAppShared/ExampleJsInterop.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ public async ValueTask<string> Prompt(string message)
2727
return await module.InvokeAsync<string>("showPrompt", message);
2828
}
2929

30+
public async ValueTask UpdateControlDiv(string newValue)
31+
{
32+
var module = await moduleTask.Value;
33+
await module.InvokeVoidAsync("updateControlDiv", newValue);
34+
}
35+
3036
public async ValueTask DisposeAsync()
3137
{
3238
if (moduleTask.IsValueCreated)

src/BlazorWebView/samples/WebViewAppShared/wwwroot/exampleJsInterop.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,8 @@
44
export function showPrompt(message) {
55
return prompt(message, 'Type anything here');
66
}
7+
8+
export function updateControlDiv(newValue) {
9+
let controlDiv = document.getElementById('controlDiv');
10+
controlDiv.innerHTML = newValue;
11+
}

src/BlazorWebView/src/Maui/Android/BlazorWebViewHandler.Android.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Threading.Tasks;
23
using Android.Webkit;
34
using Microsoft.Extensions.DependencyInjection;
45
using Microsoft.Extensions.FileProviders;
@@ -142,5 +143,22 @@ internal IFileProvider CreateFileProvider(string contentRootDir)
142143
{
143144
return new AndroidMauiAssetFileProvider(Context.Assets, contentRootDir);
144145
}
146+
147+
/// <summary>
148+
/// Calls the specified <paramref name="workItem"/> asynchronously and passes in the scoped services available to Razor components.
149+
/// </summary>
150+
/// <param name="workItem">The action to call.</param>
151+
/// <returns>Returns a <see cref="Task"/> representing <c>true</c> if the <paramref name="workItem"/> was called, or <c>false</c> if it was not called because Blazor is not currently running.</returns>
152+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="workItem"/> is <c>null</c>.</exception>
153+
public virtual async Task<bool> TryDispatchAsync(Action<IServiceProvider> workItem)
154+
{
155+
ArgumentNullException.ThrowIfNull(workItem);
156+
if (_webviewManager is null)
157+
{
158+
return false;
159+
}
160+
161+
return await _webviewManager.TryDispatchAsync(workItem);
162+
}
145163
}
146164
}

src/BlazorWebView/src/Maui/BlazorWebView.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Threading.Tasks;
23
using Microsoft.AspNetCore.Components.Web;
34
using Microsoft.Extensions.FileProviders;
45
using Microsoft.Maui.Controls;
@@ -75,6 +76,26 @@ public virtual IFileProvider CreateFileProvider(string contentRootDir)
7576
return ((BlazorWebViewHandler)(Handler!)).CreateFileProvider(contentRootDir);
7677
}
7778

79+
/// <summary>
80+
/// Calls the specified <paramref name="workItem"/> asynchronously and passes in the scoped services available to Razor components.
81+
/// </summary>
82+
/// <param name="workItem">The action to call.</param>
83+
/// <returns>Returns a <see cref="Task"/> representing <c>true</c> if the <paramref name="workItem"/> was called, or <c>false</c> if it was not called because Blazor is not currently running.</returns>
84+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="workItem"/> is <c>null</c>.</exception>
85+
#if ANDROID
86+
[System.Runtime.Versioning.SupportedOSPlatform("android23.0")]
87+
#endif
88+
public virtual async Task<bool> TryDispatchAsync(Action<IServiceProvider> workItem)
89+
{
90+
ArgumentNullException.ThrowIfNull(workItem);
91+
if (Handler is null)
92+
{
93+
return false;
94+
}
95+
96+
return await ((BlazorWebViewHandler)(Handler!)).TryDispatchAsync(workItem);
97+
}
98+
7899
void IBlazorWebView.UrlLoading(UrlLoadingEventArgs args) =>
79100
UrlLoading?.Invoke(this, args);
80101

src/BlazorWebView/src/Maui/PublicAPI/net-android/PublicAPI.Unshipped.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.StartPath.set -> void
44
Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.StartPath.get -> string!
55
Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.StartPath.set -> void
66
static readonly Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.StartPathProperty -> Microsoft.Maui.Controls.BindableProperty!
7+
virtual Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.TryDispatchAsync(System.Action<System.IServiceProvider!>! workItem) -> System.Threading.Tasks.Task<bool>!
8+
virtual Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler.TryDispatchAsync(System.Action<System.IServiceProvider!>! workItem) -> System.Threading.Tasks.Task<bool>!

src/BlazorWebView/src/Maui/PublicAPI/net-ios/PublicAPI.Unshipped.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.StartPath.set -> void
44
Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.StartPath.get -> string!
55
Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.StartPath.set -> void
66
static readonly Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.StartPathProperty -> Microsoft.Maui.Controls.BindableProperty!
7+
virtual Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.TryDispatchAsync(System.Action<System.IServiceProvider!>! workItem) -> System.Threading.Tasks.Task<bool>!
8+
virtual Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler.TryDispatchAsync(System.Action<System.IServiceProvider!>! workItem) -> System.Threading.Tasks.Task<bool>!

src/BlazorWebView/src/Maui/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.StartPath.set -> void
44
Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.StartPath.get -> string!
55
Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.StartPath.set -> void
66
static readonly Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.StartPathProperty -> Microsoft.Maui.Controls.BindableProperty!
7+
virtual Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.TryDispatchAsync(System.Action<System.IServiceProvider!>! workItem) -> System.Threading.Tasks.Task<bool>!
8+
virtual Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler.TryDispatchAsync(System.Action<System.IServiceProvider!>! workItem) -> System.Threading.Tasks.Task<bool>!

0 commit comments

Comments
 (0)