use Kestrel in .NET Core worker project
Asked Answered
A

2

6

I created a new .NET Core worker project with the template provided by Visual Studio. I want to listen for incoming TCP messages and HTTP requests. I'm following David Fowler's "Multi-protocol Server with ASP.NET Core and Kestrel" repository on how to setup Kestrel.

AFAIK all I have to do is to install the Microsoft.AspNetCore.Hosting package to get access to the UseKestrel method.

In the Program.cs file I'm currently doing this

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService<Worker>();
            });
}

Unfortunately I can't append UseKestrel to the ConfigureServices method. I think this is because I'm working with the IHostBuilder interface instead of the IWebHostBuilder interface.

This project should not be a Web API project, it should remain as a Worker project.

Any ideas how to configure Kestrel for this?


I tried to change the code to the code from the sample repository

using System.Net;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace Service
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureServices(services =>
                {
                    // ...
                })
                .UseKestrel(options =>
                {
                    // ...
                });
    }
}

When doing so it is still not able to resolve WebHost and comes up with these errors

  • There is no argument given that corresponds to the required formal parameter 'middleware' of 'ConnectionBuilderExtensions.Run(IConnectionBuilder, Func<ConnectionContext, Task>)'

  • The name 'WebHost' does not exist in the current context

I think this happens because the worker project does not use a Web SDK.

Achromatic answered 7/9, 2020 at 9:34 Comment(2)
As far as I know kestrel is an extension of webhostbuilder. If you need a web server in your console app then use webhostbuilder in your program.csCatamenia
Hmm I tried it but it didn't work ... I updated my questionAchromatic
C
6

You enable the HTTP workload using IHostbuilder you need to add .ConfigureWebHostDefaults in your Host.CreateDefaultBuilder. Since Kestrel is web server you can only configure it from a webhost.

In your program.cs file

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                   webBuilder.UseStartup<Startup>();
                    webBuilder.UseKestrel(options =>
                    {
                        // TCP 8007
                        options.ListenLocalhost(8007, builder =>
                        {
                            builder.UseConnectionHandler<MyEchoConnectionHandler>();
                        });

                        // HTTP 5000
                        options.ListenLocalhost(5000);

                        // HTTPS 5001
                        options.ListenLocalhost(5001, builder =>
                        {
                            builder.UseHttps();
                        });
                    });
                });

Or

public static IHostBuilder CreateHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .UseKestrel(options =>
            {
                // TCP 8007
                options.ListenLocalhost(8007, builder =>
                {
                    builder.UseConnectionHandler<MyEchoConnectionHandler>();
                });

                // HTTP 5000
                options.ListenLocalhost(5000);

                // HTTPS 5001
                options.ListenLocalhost(5001, builder =>
                {
                    builder.UseHttps();
                });
            });

Since you are enabling HTTP workloads using a web server then you project must be of type web. WebHost will be enabled only if the project is of type web. So you need to change your SDK to use web in your csproj file.

<Project Sdk="Microsoft.NET.Sdk.Web">

Reference:

Catamenia answered 7/9, 2020 at 12:30 Comment(0)
T
6

NET 5.0 as follow

  1. Add Framework reference to ASP.NET:

    <Project Sdk="Microsoft.NET.Sdk.Worker">
        <ItemGroup>
            <FrameworkReference Include="Microsoft.AspNetCore.App" />
        </ItemGroup>
    </Project>
    
  2. Add web configuration on program.cs

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseWindowsService()
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false);
                config.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", optional: true);
    
                Configuration = config.Build();
             })
    
             //Worker
             .ConfigureServices((hostContext, services) =>
             {
                 services.AddHostedService<ServiceDemo>();
             })
    
             // web site
             .ConfigureWebHostDefaults(webBuilder =>
             {
                 webBuilder.UseStartup<Startup>();
                 webBuilder.UseKestrel(options =>
                 {
                     // HTTP 5000
                     options.ListenLocalhost(58370);
    
                     // HTTPS 5001
                     options.ListenLocalhost(44360, builder =>
                     {
                         builder.UseHttps();
                     });
                 });
             });
    
  3. Configure Startup

    public class Startup
    {
        public IConfiguration Configuration { get; }
    
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
    
        public void ConfigureServices(IServiceCollection services)
        {
        }
    
        public void Configure(IApplicationBuilder app)
        {
            var serverAddressesFeature = app.ServerFeatures.Get<IServerAddressesFeature>();
    
            app.UseStaticFiles();
            app.Run(async (context) =>
            {
                context.Response.ContentType = "text/html";
                await context.Response
                    .WriteAsync("<!DOCTYPE html><html lang=\"en\"><head>" +
                                "<title></title></head><body><p>Hosted by Kestrel</p>");
    
                if (serverAddressesFeature != null)
                {
                    await context.Response
                        .WriteAsync("<p>Listening on the following addresses: " +
                                    string.Join(", ", serverAddressesFeature.Addresses) +
                                    "</p>");
                }
    
                await context.Response.WriteAsync("<p>Request URL: " +
                                                  $"{context.Request.GetDisplayUrl()}<p>");
            });
        }
    }
    
Taurus answered 8/3, 2021 at 20:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.