Watson.Extensions.Hosting 1.0.2

dotnet add package Watson.Extensions.Hosting --version 1.0.2
                    
NuGet\Install-Package Watson.Extensions.Hosting -Version 1.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Watson.Extensions.Hosting" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Watson.Extensions.Hosting" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Watson.Extensions.Hosting" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Watson.Extensions.Hosting --version 1.0.2
                    
#r "nuget: Watson.Extensions.Hosting, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Watson.Extensions.Hosting@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Watson.Extensions.Hosting&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Watson.Extensions.Hosting&version=1.0.2
                    
Install as a Cake Tool

Watson Extensions for Modern .NET Hosting

NuGet Version Build Status License: MIT

Watson.Extensions.Hosting brings the power and flexibility of Microsoft.Extensions.Hosting (the .NET Generic Host) to the lightweight and high-performance WatsonWebserver. This library empowers you to build web servers using modern, familiar patterns like Dependency Injection, Middleware, MVC-style Controllers, and Minimal APIs, just as you would with ASP.NET Core.

It's the ideal solution for creating lightweight microservices, internal APIs, or self-hosted applications without the overhead of a full-fledged framework, but with all the benefits of the .NET hosting ecosystem.

πŸ€” Why Watson Extensions for Hosting?

While WatsonWebserver is an excellent standalone server, integrating it into a modern .NET application often requires boilerplate code to manage its lifecycle, configuration, and dependencies. This library bridges that gap by providing a seamless, out-of-the-box integration with the .NET Generic Host, allowing you to focus on your application's logic instead of its infrastructure.

✨ Core Features

  • Generic Host Integration: Manage your Watson server's lifecycle (StartAsync, StopAsync) automatically within the .NET IHost.
  • Full Dependency Injection (DI) Support: Leverage the built-in DI container to manage your services with configurable lifetimes (Singleton, Scoped, Transient).
  • ASP.NET Core Style Routing:
    • Controllers: Define your APIs in clean, organized classes using familiar attributes like [Route], [HttpGet], and [HttpPost].
    • Minimal APIs: Quickly map endpoints to simple delegate handlers using MapGet, MapPost, etc., for small-scale APIs or prototyping.
  • Advanced Model Binding: Automatically populate your action method parameters from the request's route, query string, headers, and body.
  • Extensible Middleware Pipeline: Inject custom logic into the request processing pipeline for tasks like logging, authentication, or error handling.
  • Flexible Implementation: Works with both the full WatsonWebserver and the dependency-free WatsonWebserver.Lite.

πŸš€ Getting Started

Let's build your first application in just a few minutes.

1. Prerequisites

2. Installation

First, install our main package via the .NET CLI.

dotnet add package Watson.Extensions.Hosting

Next, you need to choose which WatsonWebserver implementation to use. Both are part of the excellent WatsonWebserver project. WatsonWebserver.Lite is a great choice for simple, dependency-free projects.

dotnet add package Watson.Lite
# OR for the full version
dotnet add package Watson

3. Configure Your Server

Now, let's set up a simple Console Application. Replace the content of your Program.cs with the following code. We'll define a controller and a minimal API endpoint.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Watson.Extensions.Hosting;
using Watson.Extensions.Hosting.Controllers;
using Watson.Extensions.Hosting.Core;
using WatsonWebserver.Lite; // Using the 'Lite' version for this example

// --- 1. Define a Controller ---
// This is a class-based approach to organizing your endpoints.
[Route("api/greeting")]
public class GreetingController : ControllerBase
{
    // This action will handle GET requests to /api/greeting/{name}
    [HttpGet("{name}")]
    public IActionResult SayHello([FromRoute] string name)
    {
        // The Results helper creates standard HTTP responses.
        // Here, we return a 200 OK with a JSON payload.
        return Results.Ok(new { message = $"Hello, {name}!" });
    }
}

// --- 2. Configure the .NET Host ---
var builder = Host.CreateDefaultBuilder(args);

builder.ConfigureServices((_, services) =>
{
    // This is where you add the Watson Webserver to the service collection.
    services.AddWatsonWebserver<WebserverLite>(options =>
    {
        options.Port = 8080;
        options.Hostname = "localhost";

        // This method scans the current assembly for any class inheriting
        // from ControllerBase and automatically registers its routes.
        options.MapControllers();

        // You can also define simple endpoints directly, Minimal API style.
        options.MapGet("/", () => Results.Ok("Welcome to Watson.Extensions.Hosting!"));
    });
});

// --- 3. Build and Run the Application ---
var app = builder.Build();

Console.WriteLine("Server is listening on http://localhost:8080");
Console.WriteLine("Press CTRL+C to exit.");
await app.RunAsync();

4. Run and Test

Execute your application from the terminal:

dotnet run

You can now test your endpoints using a web browser or a tool like cURL or Postman:

  • GET http://localhost:8080/
    • Will respond with the plain text: "Welcome to Watson.Extensions.Hosting!"
  • GET http://localhost:8080/api/greeting/World
    • Will respond with the JSON: {"message":"Hello, World!"}

πŸ“š In-Depth Guide

Dependency Injection

Register your custom services in the DI container and inject them anywhere you needβ€”in your controllers, middleware, or Minimal API handlers.

1. Define and Register a Service Let's create a simple service to manage some state.

// MyAwesomeService.cs
public class MyAwesomeService
{
    private int _requestCount = 0;
    public int GetRequestCount() => Interlocked.Increment(ref _requestCount);
}

Now, register it as a singleton in Program.cs:

// In the builder.ConfigureServices block:
services.AddSingleton<MyAwesomeService>();

2. Inject the Service into a Controller The service is automatically provided to the controller's constructor.

[Route("api/stats")]
public class StatsController : ControllerBase
{
    private readonly MyAwesomeService _service;

    // The DI container injects an instance of MyAwesomeService here.
    public StatsController(MyAwesomeService service)
    {
        _service = service;
    }

    [HttpGet("requests")]
    public IActionResult GetRequestCount()
    {
        var count = _service.GetRequestCount();
        return Results.Ok(new { totalRequests = count });
    }
}

3. Inject the Service into a Minimal API Handler Just add the service as a parameter to your handler delegate and mark it with [FromServices].

// In services.AddWatsonWebserver:
options.MapGet("/stats", ([FromServices] MyAwesomeService service) =>
{
    var count = service.GetRequestCount();
    return Results.Ok(new { totalRequests = count });
});

Model Binding

This library automatically maps data from an incoming HTTP request to the parameters of your action methods.

Here is a comprehensive example showing all available sources:

[Route("api/products")]
public class ProductsController : ControllerBase
{
    [HttpPost("{id}")]
    public IActionResult CreateProduct(
        [FromRoute] int id,                     // From the URL path: /api/products/123
        [FromQuery] string? category,          // From the query string: ?category=electronics
        [FromHeader("X-Api-Key")] string apiKey, // From a request header
        [FromBody] ProductDto product,          // Deserialized from the JSON request body
        [FromServices] ILogger<ProductsController> logger) // Injected from DI
    {
        logger.LogInformation("Creating product {ProductId} in category {Category} with API key {ApiKey}", id, category, apiKey);
        // ... process product data ...
        return Results.Ok(new { status = "Product created", id = id, name = product.Name });
    }
}

public class ProductDto
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Middleware

Build a custom request processing pipeline to handle cross-cutting concerns. Middleware is executed in the order it is registered.

1. Create a Middleware Class A middleware is any class that implements the IMiddleware interface.

public class RequestLoggingMiddleware : IMiddleware
{
    private readonly ILogger<RequestLoggingMiddleware> _logger;

    public RequestLoggingMiddleware(ILogger<RequestLoggingMiddleware> logger)
    {
        _logger = logger;
    }

    // This method is the core of the middleware.
    public async Task InvokeAsync(WatsonHttpContext context, Func<HttpContextBase, Task> next)
    {
        var request = context.HttpContextBase.Request;
        _logger.LogInformation("Request received: {Method} {Path}", request.Method, request.Url.Raw);

        // Call the 'next' delegate to pass control to the next middleware in the pipeline.
        // If this is the last middleware, it calls the final endpoint handler.
        await next(context.HttpContextBase);
    }
}

2. Register the Middleware Add your middleware to the pipeline within the server configuration. The order matters!

services.AddWatsonWebserver<WebserverLite>(options =>
{
    // ... other options
    
    // Requests will pass through RequestLoggingMiddleware first.
    options.UseMiddleware<RequestLoggingMiddleware>();
});

🀝 How to Contribute

We welcome contributions from the community! Whether it's a bug fix, a new feature, or a documentation improvement, your help is greatly appreciated.

  1. Report Bugs: If you find an issue, please open an issue and provide detailed steps to reproduce it.
  2. Suggest Features: Have a great idea? Open an issue to start a discussion.
  3. Submit Pull Requests: Feel free to fork the repository, create a new branch for your changes, and open a Pull Request when you're ready.

For detailed contributing guidelines, please refer to the CONTRIBUTING.md file.

❀️ Support the Project

The easiest way to show your support is by starring the repository on GitHub! ⭐

This helps raise the project's visibility and motivates us to keep improving it.

πŸ™ Acknowledgements

This project is built upon and extends the fantastic work of the WatsonWebserver library. A big thank you to its author and contributors for creating such a reliable and performant foundation.

πŸ“œ License

This project is licensed under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Watson.Extensions.Hosting:

Package Downloads
Watson.Extensions.Hosting.Samples.Default

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 114 9/5/2025
1.0.0 109 9/5/2025