Codebelt
v10.5.5

Cuemon.Net

Adds query-string helpers, testable HTTP workflows, URI change watchers, and batched SMTP delivery on top of System.Net.

.NET 10.0 / .NET 9.0 / .NET Standard 2.0 MIT 95,643 downloads

Overview

Cuemon.Net adds a focused set of networking primitives on top of the framework HTTP, SMTP, and URI APIs. Its surface covers query-string parsing and formatting, URL encoding helpers, an HttpClient wrapper with verb-specific convenience methods, change detection for remote resources, and batched mail delivery.

It is most useful when you want repeatable outbound HTTP setup, lightweight monitoring of remote resources, or query-string handling that preserves repeated keys without pulling in a larger web stack.

Key APIs

HttpManager wraps HttpClient creation and exposes verb-specific asynchronous methods such as HttpGetAsync, HttpHeadAsync, HttpPostAsync, HttpPutAsync, HttpPatchAsync, HttpDeleteAsync, HttpOptionsAsync, and HttpTraceAsync. Its virtual HttpAsync(Uri, Action<HttpRequestOptions>) overload is the escape hatch when you need to configure the request message directly.

HttpManagerOptions configures the handler factory, default request headers, timeout, and handler disposal behavior used by the HttpManager(Action<HttpManagerOptions>) constructor. The defaults are opinionated but explicit: keep-alive headers, automatic GZip and Deflate decompression, up to 10 redirects, and a two-minute timeout.

HttpRequestOptions carries the HttpRequestMessage and inherited asynchronous options for a single HttpManager call. Its CompletionOption switches to ResponseHeadersRead for HEAD and TRACE, which makes those requests avoid buffering a response body.

HttpWatcher extends the Cuemon watcher model to monitor a Uri for change notifications. It uses HEAD requests by default and raises Changed when Last-Modified or ETag values move, or when a computed checksum changes if response-body reading is enabled.

HttpWatcherOptions configures how HttpWatcher resolves HttpClient and hashing dependencies and whether the response body should participate in change detection. By default it creates an HttpClient with automatic decompression and uses CyclicRedundancyCheck64 when body hashing is turned on.

HttpDependency connects one or more lazily created HttpWatcher instances to the broader Cuemon dependency abstraction. The watchers are only materialized when the dependency starts, which lets you defer remote monitoring setup until runtime.

QueryStringCollection models a URI query string as both a NameValueCollection and an IReadOnlyCollection<KeyValuePair<string, string>>. Its string constructor parses duplicate keys, and ToString() reconstructs an ampersand-separated query string with the expected leading ?.

StringDecoratorExtensions.UrlEncode and StringDecoratorExtensions.UrlDecode give the decorator-based string API package-local URL encoding and decoding behavior. They are also used internally when query-string values are decoded and re-encoded.

MailDistributor batches MailMessage instances across new SmtpClient deliveries created by a supplied factory. SendAsync partitions the outgoing messages by delivery size, while SendOneAsync keeps the same batching and filtering behavior for a single message.

Basic usage

using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Codebelt.Extensions.Xunit;
using Cuemon.Net.Http;
using Xunit;

namespace MyProject.Tests;

public class HttpManagerTest : Test
{
    public HttpManagerTest(ITestOutputHelper output) : base(output)
    {
    }

    [Fact]
    public async Task ShouldApplyConfiguredHeaders_ToOutboundRequest()
    {
        using var handler = new RecordingHandler();
        using var sut = new HttpManager(options =>
        {
            options.HandlerFactory = () => handler;
            options.DefaultRequestHeaders["X-Correlation-Id"] = "import-job-42";
        });

        using var response = await sut.HttpGetAsync(new Uri("https://example.test/import/status"));
        var payload = await response.Content.ReadAsStringAsync();

        Assert.Equal(HttpMethod.Get, handler.LastMethod);
        Assert.Equal("import-job-42", handler.LastCorrelationId);
        Assert.Equal("{\"status\":\"ok\"}", payload);

        TestOutput.WriteLine($"Request completed with payload: {payload}");
    }

    private sealed class RecordingHandler : HttpMessageHandler
    {
        public HttpMethod? LastMethod { get; private set; }

        public string? LastCorrelationId { get; private set; }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            LastMethod = request.Method;
            if (request.Headers.TryGetValues("X-Correlation-Id", out var values))
            {
                LastCorrelationId = string.Join(",", values);
            }

            return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StringContent("{\"status\":\"ok\"}", Encoding.UTF8, "application/json")
            });
        }
    }
}

Use this pattern when you want verb-specific HttpManager calls while still controlling handlers and shared headers in one place. It matters because the package lets you test outbound HTTP behavior without touching a real endpoint.

Installation

dotnet add package Cuemon.Net

Usage guidance

Adopt Cuemon.Net when you need lightweight wrappers around HttpClient, watcher-based monitoring of remote resources, query-string round-tripping with repeated keys, or batched SMTP delivery. If you only need one-off framework HTTP calls or basic URL encoding, the built-in APIs are smaller, and if you need factory-managed HttpManager integration, Cuemon.Extensions.Net is the better sibling package.

Family packages