dotnet / MobileBlazorBindings

Experimental Mobile Blazor Bindings - Build native and hybrid mobile apps with Blazor
MIT License
1.2k stars 175 forks source link

Add support for hosting Blazor Web components directly in WPF (.NET Core) #313

Closed Eilon closed 3 years ago

Eilon commented 3 years ago

To simplify some common scenarios we should add support for directly hosting Blazor Web components in WPF (.NET Core) applications. This would use Edge WebView2 directly but still re-use many of the same APIs and patterns used elsewhere in Mobile Blazor Bindings.

The work is to:

  1. Factor out much of the hybrid-related code into a new Microsoft.MobileBlazorBindings.Hosting project
  2. Change existing MBB to use the new shared Hosting project
  3. Create a new Microsoft.MobileBlazorBindings.WPF project that uses WebView2 and the shared Hosting logic

Ideally this wouldn't change or break any existing MBB applications because all the old APIs should still exist. But there could be a namespace change here or there. We'll see, but not a big deal.

dcuccia commented 3 years ago

This is great!

Eilon commented 3 years ago

This is what a simple sample app looks like:

XAML:

    <DockPanel Margin="6">
        <StackPanel Margin="6" Orientation="Horizontal" DockPanel.Dock="Top" Background="CadetBlue">
            <Label>This is native WPF UI</Label>
            <Button Click="Button_Click" Padding="6" Margin="3">Click to see counter value</Button>
        </StackPanel>
        <blazorwpf:BlazorWebView HorizontalAlignment="Stretch" VerticalAlignment="Stretch" x:Name="MyBlazorWebView" />
    </DockPanel>

Screenshot: (top blue-ish section is WPF XAML, bottom section is Blazor Web rendering HTML into a WebView2):

image

RChrisCoble commented 3 years ago

So this removes the need for Xamarin?

Also, how difficult is this to port to .Net 5 (if it isn't already).

Keep up the great work @Eilon !!!

Eilon commented 3 years ago

@RChrisCoble thanks! Yes this is .NET Core 3.1 + WPF + Blazor, so it should work fine on .NET 5 as well. It's only for Blazor Web components. This doesn't have the ability to use Blazor to write native UI (which I think isn't what you were wanting to use right now anyway).

Eilon commented 3 years ago

WPF sample app is here: https://github.com/xamarin/MobileBlazorBindings/tree/master/samples/WpfBlazorSample/WpfBlazorSample

And it uses this standard Razor Class Library (RCL) as its web content: https://github.com/xamarin/MobileBlazorBindings/tree/master/samples/SharedProjects/RazorClassLibrarySample

Jinjinov commented 3 years ago

This is really great, exactly what I wanted! Can I use this in my app? I can't find a Microsoft.MobileBlazorBindings.WPF NuGet - does this exist in a NuGet with a different name?

IvanJosipovic commented 3 years ago

@Jinjinov, its only available in the nightly feed at the moment.

See here, https://docs.microsoft.com/en-us/mobile-blazor-bindings/contribute/nightly-builds

Jinjinov commented 3 years ago

If I try to use it with .NET 5

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net5.0-windows</TargetFramework>
    <LangVersion>latest</LangVersion>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.MobileBlazorBindings.WPF" Version="0.6.69-preview" />
  </ItemGroup>

it throws this exception:

System.TypeLoadException
  HResult=0x80131522
  Message=Method 'BeginInvokeJS' in type 'Microsoft.MobileBlazorBindings.Hosting.BlazorHybridJSRuntime' from assembly 'Microsoft.MobileBlazorBindings.Hosting, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
  Source=Microsoft.MobileBlazorBindings.Hosting
  StackTrace:
   at Microsoft.Extensions.DependencyInjection.BlazorHybridServiceCollectionExtensions.AddBlazorHybrid(IServiceCollection services)
   at WpfBlazorSample.MainWindow.<>c.<.ctor>b__0_0(HostBuilderContext hostContext, IServiceCollection services) in C:\WpfBlazorSample\MainWindow.xaml.cs:line 25

The only change I made to the WpfBlazorSample was to remove every use of RazorClassLibrarySample

Eilon commented 3 years ago

Mobile Blazor Bindings currently requires .NET Core 3.1. It will eventually require .NET 6 due to some changes that will be required. It could be that with .NET 5 there are some breaking changes that are not accounted for.

@Jinjinov - can you log a new issue for the exception that you're seeing so that we can take a look?

Jinjinov commented 3 years ago

@Eilon Added #339

Approximately when will MBB nightly builds start using .NET 6? In a few days / weeks / months?

Eilon commented 3 years ago

@Jinjinov thanks for logging the new issue!

Approximately when will MBB nightly builds start using .NET 6? In a few days / weeks / months?

Probably weeks. I just discussed this a few minutes ago with my Blazor colleagues and once we get a few more things up and running in the official .NET 6 repo I will start the upgrade to .NET 6!

b-straub commented 3 years ago

Is the dotnet6 branch sample "WpfNewBlazorSample" already supposed to to something useful? It compiles without problems but no razor component will be shown.

Eilon commented 3 years ago

@b-straub that's where we were experimenting with the new .NET 6 work, which is now in the ASP.NET Core repo here: https://github.com/dotnet/aspnetcore/tree/main/src/Components/WebView

The remaining work (non-trivial) is to change this repo to depend on .NET 6 and use the new abstractions. I'm working on some related areas right now, such as enabling .NET MAUI, and that should pave the path towards moving this repo to .NET 6.

Jinjinov commented 3 years ago

@Eilon at the link that you provided there is Microsoft.AspNetCore.Components.WebView.WebView2.IWebView2Wrapper that wraps Microsoft.Web.WebView2.Core.CoreWebView2 - do you have plans to also support the WebView2 control on macOS and Linux? Would it be hard to get a working proof of concept?

Eilon commented 3 years ago

Hi @Jinjinov when there's full support for WebView2 on non-Windows platforms it's definitely something we will take a look at.

b-straub commented 3 years ago

Thanks @Eilon for the link to the sample code. Yesterday I got something working by pulling out the WinForms example and the Microsoft.AspNetCore.Components.WebView.WebView2 + Microsoft.AspNetCore.Components.WebView.WindowsForms project. My complex Razor page appeared, but using RCL and third-party components didn't work well (had to manually include the static assets) and some other issues with JS and CSS (isolation) were also present.

In the latest Nightly builds, the relevant packages are now released, but I can't even get the WinForms/WPF example to work again. The WebView loads, but instead of the content it comes up with an ERR_ADDRESS_INVALID (https://0.0.0.0). I assume it is work in progress and still a bit too early for serious testing.

b-straub commented 3 years ago

@Eilon please check Exception thrown from StaticContentProvider._manifestProvider

After removing the error string resource as workaround all is working well.

dcuccia commented 3 years ago

For those that land here looking for the latest on the WPF and WinForms BlazorWebView, it arrived today with .NET 6.0 Preview 3:

https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-3/

Jinjinov commented 3 years ago

@Eilon Looking at https://github.com/dotnet/aspnetcore/tree/main/src/Components/WebView/Samples - thank you for your hard work!

There are many duplicate files in the BlazorWinFormsApp and BlazorWpfApp folders.

Just out of curiosity, which files could be moved to WebviewAppShared?

I am guessing that Index.razor, Other.razor and AppState.cs could go to WebviewAppShared without a problem?

What about app.css, index.html, _Imports.razor and Main.razor?

Could any of them be moved to WebviewAppShared? That would be very convenient for my Blazor PWA as I could make a Windows desktop app easier :)

FelipeCostaGualberto commented 3 years ago

Hello! I'm trying to use WPF (.NET 5) with these steps, already with nightly builds (0.6.69-preview), but when I try to run, I get: TypeLoadException: Method 'BeginInvokeJS' in type 'Microsoft.MobileBlazorBindings.Hosting.BlazorHybridJSRuntime' from assembly 'Microsoft.MobileBlazorBindings.Hosting, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation. Do you know how can I fix this?

Eilon commented 3 years ago

@FelipeCostaGualberto that looks like https://github.com/dotnet/MobileBlazorBindings/issues/339, which doesn't seem to be fixed yet.