Host Kestrel Web Server in .NET 6 Windows Form Application

Jason Ge
3 min readAug 25, 2022

In some cases, we may need to host a web server inside a Windows Forms application and serve either static content or even RESTful APIs.

Kestrel is a cross-platform web server for ASP.NET Core. Kestrel is the web server that’s included and enabled by default in ASP.NET Core Web project templates. For more information about Kestrel web server, you can visit Microsoft web site: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-6.0

In this article, we will discuss how to host Kestrel web server in Windows Forms application to serve static web content and Web API.

internal static class Program
{
[STAThread]
static void Main()
{
Task.Run(() => StartWebServer());
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
private static void StartWebServer()
{
var builder = WebHost.CreateDefaultBuilder();
var app = builder
.UseKestrel(options => options.Listen(IPAddress.Parse(“127.0.0.1”), 8888))
.UseContentRoot(Directory.GetCurrentDirectory())
.UseWebRoot(Path.Combine(Directory.GetCurrentDirectory(), “wwwroot”))
.Configure(app =>
{
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), “wwwroot”)),
RequestPath = “/”
});
}).Build();
app.Run();
}

Since we are hosting the Kestrel web server inside regular Windows Forms app, we need to create and run the Kestrel web server hosting in a different task.

First we call WebHost.CreateDefaultBuilder() to create a web host builder. Then we add the Kestrel web server and add static file middleware into the pipeline.

By default, Kestrel web server listens on http://localhost:5000/. You can change the IP address and port number you would like Kestrel web server to bind to by passing them to the overload UseKestrel() method:

.UseKestrel(options => options.Listen(IPAddress.Parse(“127.0.0.1”), 8888))

Static Content

By default, ASP.NET Core doesn’t have built-in support for static files. To serve static files from an ASP.NET Core app, you must use and configure static files middleware. In .NET Core, you can call app.UseStaticFiles() to use the static file middleware.

ContentRoot vs WebRoot

I found this article explained the difference of these two terms pretty well: https://referbruv.com/blog/understanding-contentroot-and-webroot-in-asp-net-core-simplified/

ContentRootPath is where the Host looks for the executables and assemblies to run. by default it is the current directory when the application is run.

WebRootPath is the base path for all the static files served by the application, such as CSS, JavaScript or Image files. It is actually a sub path of the ContentRootPath.

Our configuration sets the web root folder to “wwwroot” (It is the default setting, by the way). Therefore, you can put the static content into the “wwwroot” folder under the application root folder, for example index.html. You can access this index html using the URL: http://localhost:8888/index.html

In our Visual Studio project, we need to add framework reference and nuget package reference as following:

<Project Sdk=”Microsoft.NET.Sdk”>
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include=”Microsoft.Extensions.Hosting” Version=”6.0.1" />
</ItemGroup>
<ItemGroup>
<FrameworkReference Include=”Microsoft.AspNetCore.App” /></ItemGroup>
</Project>

Host Web API

We can also host Web API inside the Windows Forms app using Kestrel. In order to do that, we just need to add more configurations to the web host builder:

private static void StartWebServer()
{
var builder = WebHost.CreateDefaultBuilder();
var app = builder
.UseKestrel(options => options.Listen(IPAddress.Parse(“127.0.0.1”), 8888))
.UseContentRoot(Directory.GetCurrentDirectory())
.UseWebRoot(Path.Combine(Directory.GetCurrentDirectory(), “wwwroot”))
.ConfigureServices((services) =>
{
services.AddControllers().AddNewtonsoftJson();
services.AddCors();
})

.Configure(app =>
{
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), “wwwroot”)),
RequestPath = “/”
});
app.UseRouting();
app.UseCors(builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});

}).Build();
app.Run();
}

Remember to add following to nuget packages in order for above code to compile:

  • Microsoft.AspNetCore.Mvc.NewtonsoftJson
  • Microsoft.Extensions.DependencyInjection

Then you can create your Web API controllers inside Controllers folder. For example, the following task controller:

[ApiController]
[Route("api/v1.0/[controller]")]
public class TasksController : ControllerBase
{
public TasksController(){}
[HttpGet("")]
public IActionResult Get()
{
return Ok("hello world");
}
}

After build and run, you can then access your task API Get operation using following link:

http://localhost:8888/api/v1.0/tasks

Happy coding!

--

--

Jason Ge

Software developer with over 20 years experience. Recently focus on Vue/Angular and asp.net core.