1

dotnet core 3 is out! So, I need to host aspnetcore inside a WPF application.

Tried this approach but since VS uses csproj Project node to determine the output, it doesn't work.

There is two nuget packages that called my attention:

Microsoft.AspNetCore.Mvc.Razor.Extensions

AND

Microsoft.Extensions.Hosting

But have no idea how to implement this on WPF :(

Any clues?

mxmissile
  • 11,464
  • 3
  • 53
  • 79
Alexandre
  • 7,004
  • 5
  • 54
  • 72
  • The question is why? Why do you want to host a razor website in a WPF app? – Jonathan Alfaro Jan 29 '20 at 17:47
  • Because our customers need to use the same web app in a local environment, without internet, without iis. – Alexandre Jan 29 '20 at 22:54
  • When you say a local environment you mean in a single computer or a private LAN? – Jonathan Alfaro Jan 29 '20 at 23:25
  • Also ASP.NET Core comes with an embedded web server called Kestrel. This means you can run it on your local machine without installing IIS or any other server. – Jonathan Alfaro Jan 29 '20 at 23:26
  • yes, local lan running aspnet core app without IIS. I know about Kestrel and in the question there is an approach working with dotnet core 2, the question is about dotnet core 3. – Alexandre Jan 30 '20 at 12:15
  • regardless of .Net Core 2.2 or 3.1.... why do you need to host it in a WPF app? If all you want is to run the website you do not need WPF at all. Why do you need WPF? is there other functionality aside from the website? – Jonathan Alfaro Jan 30 '20 at 15:50
  • 1
    Jonathan the point here is not the business, but technically how to do this – Alexandre Jan 30 '20 at 19:41
  • Well running the website in kestrel is just a command line call.... So you could just call it from a button or on application start.... The point is unless you really need WPF functionality there is no need to host the application in WPF. You can just create a self hosted asp.net core website. Specially if it only runs within the same machine. – Jonathan Alfaro Jan 30 '20 at 19:59
  • 1
    For example you can just publish your self contained asp.net core website to a folder and include that folder with your "WPF Launcher" when your WPF starts or perhaps on a button click you can issue a command to the command line like this "dotnet MyCoolWebsite.dll" and that will run the ASP.NET Core website or api using kestrel. And it will listen on the configured port in localhost. – Jonathan Alfaro Jan 30 '20 at 20:14
  • @Alexandre did you make it work? – Anonymous Jun 14 '20 at 00:52
  • @JonathanAlfaro hosting it from wpf itself can be beneficial. I do this with a wpf application that is running as a twitch chat bot that also uses signalR so that follow events etc are pushed to the server pages in realtime and are then fed to obs as a browser source. I have a system tray icon with the wpf app and when the main window is closed, it hides to the system tray. this allows me to start and stop both with a single process and put it in the system tray, and gain IPC between the 2 with SignalR. I have posted an answer with example code from my app I use to do this :) – Jacqueline Loriault Oct 10 '20 at 10:42
  • @Anonymous check out my answer I posted if you still need to get this type of thing working :) – Jacqueline Loriault Oct 19 '20 at 05:59

2 Answers2

3

this is actually pretty easy to do, I have done it with a twitch bot I am building you need to have both a wpf and a asp.net core website in the solution. add a project reference to your asp.net core website and right click the project and under settings change it from console app to Class libary. back in your wpf app in the App.xaml.cs code file you need to override the OnStartup and from there launch your webserver. its a little tricky at first but it works well when setup. there is one side effect to this tho and that is the wwwroot folder from the web app does not get copied at build time so you need to either manully copy it or use a post build event in the web app. this is my post build event as an example:

xcopy /E /Y "$(ProjectDir)wwwroot" "F:\Repos\StreamTools\ControlCenter\bin\Debug\netcoreapp3.1\wwwroot"

this is my App.xaml.cs :

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using StreamTools.Core;
using System.Diagnostics;
using System.Windows;

namespace StreamTools.ControlCenter
{
    public partial class App : Application
    {
        private IHost webHost;

        protected override void OnStartup(StartupEventArgs e)
        {
            webHost = Host.CreateDefaultBuilder()
                .ConfigureWebHostDefaults(builder => builder.UseStartup<Web.Startup>())
                .ConfigureAppConfiguration(configBuilder =>
                {
                    configBuilder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
                    configBuilder.AddEnvironmentVariables();
                    if (Debugger.IsAttached)
                    {
                        configBuilder.AddUserSecrets<App>();
                    }
                })
                .Build();
            webHost.StartAsync();
            webHost.Services.GetService<IHostApplicationLifetime>().ApplicationStopping.Register(OnAppStopping);
        }

        private void OnAppStopping()
        {
            webHost.Dispose();
        }

        protected override void OnExit(ExitEventArgs e)
        {
            webHost.StopAsync();
            base.OnExit(e);
        }
    }
}

Due to the way kestrel works I'm not sure if its a bug or how its just built you have to wire up the IHostApplicationLifetime and force call to the dispose method. without that event trap closing the wpf app will not stop the web server. I have not found any other option for that part.

if you want to get really fancy, you can also use SignalR for a bit of IPC communication between the wpf app and the web server. thats what I do so when messages from the bot come in they can be displayed on the page which is used in my case as an obs source for stream notifications etc.

Hope this helps you out. and happy coding

1

With WPF you can use a WebBrowser element set to the URL of your ASP.NET hosted location (localhost I'm assuming in this case). Make sure to use kestrel standalone and not IIS. I may be misunderstanding your question, but you would essentially be using WPF as a shell to display your ASP.NET web app. Not unlike what a web browser does. You would not actually be hosting from WPF.