1

Trying to set up a SignalR server in a WPF Windows application using .NET Core 3.0. All the examples I can find assume one has a startup.cs with a Configure() method where I can call UseSignalR. But I don't. I have an "App" class, derived from Application. (I may be missing something fundamental about WPF/Core/Win that is unrelated to SignalR)

Code extract:

public partial class App : Application
{
    public IServiceProvider ServiceProvider { get; private set; }

    public IConfiguration Configuration { get; private set; }

    protected override void OnStartup(StartupEventArgs e)
    {
        var builder = new ConfigurationBuilder()
         .SetBasePath(Directory.GetCurrentDirectory())
         .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

        Configuration = builder.Build();

        var serviceCollection = new ServiceCollection();
        ConfigureServices(serviceCollection);

        ServiceProvider = serviceCollection.BuildServiceProvider();

        var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
        mainWindow.Show();
    }

    private void ConfigureServices(IServiceCollection services)
    {
        services.AddTransient(typeof(MainWindow));

        services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
        {
            builder.AllowAnyOrigin()
                   .AllowAnyMethod()
                   .AllowAnyHeader();
        }));

        services.AddSignalR().AddHubOptions<TestHub>(options =>
        {
            options.EnableDetailedErrors = true;
        });
    }

So far so good, in that it at least compiles and runs, if not do anything tangible yet.

I believe I now need to actually configure the hub:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseSignalR((configure) =>
        {
            var desiredTransports =
                HttpTransportType.WebSockets |
                HttpTransportType.LongPolling;

            configure.MapHub<TestHub>("/testhub", (options) =>
            {
                options.Transports = desiredTransports;
            });
        });
    }

But this method never gets called - I don't believe it should from Application, but would from StartUp.

Finally, my hub class:

class TestHub : Hub
{
    public Task SendMessage(string user, string message)
    {
        return Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

Compiles ok but I don't think the hub is actually running so it does nothing, of course.

Is there something different I should be doing to get the hub started and configured correctly in this type of setup?

FWIW I have used SignalR in the standard .NET framework (not Core) with WinForms apps without issue, so I'm vaguely familiar with the concepts, just not familiar with the Core/WPF/Win way.

Many thanks.

GeoffM
  • 1,603
  • 5
  • 22
  • 34
  • ASP.NET Core SignalR is built on ASP.NET Core so you need to reference ASP.NET Core from your desktop application. There is a similar question posted as an issue on [GitHub](https://github.com/aspnet/SignalR-samples/issues/82). Instead of hosting SignalR in a WPF application, you might as well create a self-hosted ASP.NET Core app: https://stackoverflow.com/questions/30298458/is-it-possible-to-self-host-a-asp-net-core-application-without-iis-not-web-api?rq=1 – mm8 May 16 '19 at 09:58
  • Thanks. I'm still working on trying to understand this - not ignoring you. – GeoffM May 17 '19 at 14:36

1 Answers1

1

Steps to build a WPF application that host ASP.NET Core:

Create solution:

dotnet new sln WpfHostingAspNetCore -o WpfHostingAspNetCore
cd WpfHostingAspNetCore

Create projects:

dotnet new wpf -o src/WpfHostingAspNetCore.WpfApplication
dotnet new web -o src/WpfHostingAspNetCore.WebApplication
dotnet sln add src/*

Add project references:

cd src/WpfHostingAspNetCore.WpfApplication
dotnet add reference ../WpfHostingAspNetCore.WebApplication

Add framework referneces:

Edit WpfHostingAspNetCore.WpfApplication.csproj and insert the following line into the ItemGroup element:

<FrameworkReference Include="Microsoft.AspNetCore.App"/>

Hosting ASP.NET Core within the WPF application lifetime

App.xaml.cs

public partial class App : Application
{
    private IHost _host;

    protected override void OnStartup(StartupEventArgs e)
    {
        _host = Host.CreateDefaultBuilder(e.Args)
            .ConfigureWebHostDefaults(webHostBuilder => webHostBuilder.UseStartup<WebApplication.Startup>())
            .ConfigureServices(services =>
            {
                services.AddTransient<MainWindow>();
            })
            .Build();

        _host.Start();

        _host.Services.GetRequiredService<MainWindow>().Show();
    }

    protected override void OnExit(ExitEventArgs e) => _host.Dispose();
}

Run and test the simple web application hosted on the WPF application

dotnet run

If it works properly, you will see "Hello world" on http://localhost/

And then add your SignalR services and middlewares within the Startup class in the web application project.

Alsein
  • 4,268
  • 1
  • 15
  • 35
  • Thanks but it's the "And then add your SignalR services" bit for which I was asking for help! – GeoffM May 17 '19 at 14:37
  • Just do what I have answered, and you will find the `Configure` method in the `Startup` class, thats where you need to configure the middleware. – Alsein May 18 '19 at 05:27
  • Your code already contains how you can add signalr services (`ConfigureServices`) and middleware (`Configure`), what you need to do next is just migrating your existing code into the `Startup` class generated from these steps. – Alsein May 18 '19 at 05:29