RestWrapper 3.2.0

dotnet add package RestWrapper --version 3.2.0
                    
NuGet\Install-Package RestWrapper -Version 3.2.0
                    
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="RestWrapper" Version="3.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RestWrapper" Version="3.2.0" />
                    
Directory.Packages.props
<PackageReference Include="RestWrapper" />
                    
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 RestWrapper --version 3.2.0
                    
#r "nuget: RestWrapper, 3.2.0"
                    
#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 RestWrapper@3.2.0
                    
#: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=RestWrapper&version=3.2.0
                    
Install as a Cake Addin
#tool nuget:?package=RestWrapper&version=3.2.0
                    
Install as a Cake Tool

RestWrapper icon

RestWrapper

NuGet Version NuGet Downloads

RestWrapper is a small C# library for sending HTTP requests without rebuilding the same request, header, authorization, streaming, and response-handling code in every project.

It wraps HttpClient with a compact API for:

  • standard REST verbs
  • custom headers and content types
  • basic, bearer, and raw authorization headers
  • JSON serialization/deserialization
  • response timing metadata
  • server-sent events
  • chunked request and response workflows
  • optional caller-supplied HttpClient instances

Why RestWrapper

If you want something lighter than a full API client framework but more structured than hand-rolled HttpClient calls, RestWrapper sits in the middle:

  • request setup is explicit and easy to read
  • response access is simple for text, bytes, streams, JSON, SSE, and chunked flows
  • you can keep using your own HttpClient for DI, proxies, mTLS, custom handlers, and connection reuse
  • the library stays close to the underlying HTTP model instead of inventing a large abstraction layer

Target Frameworks

RestWrapper currently targets:

  • netstandard2.0
  • netstandard2.1
  • net462
  • net48
  • net6.0
  • net8.0
  • net10.0

Install

dotnet add package RestWrapper

Quick Start

Simple GET:

using RestWrapper;

using RestRequest request = new RestRequest("https://api.example.com/status");
using RestResponse response = await request.SendAsync();

Console.WriteLine(response.StatusCode);
Console.WriteLine(response.DataAsString);

Simple POST:

using RestWrapper;
using System.Net.Http;

using RestRequest request = new RestRequest("https://api.example.com/messages", HttpMethod.Post);
request.ContentType = "text/plain";

using RestResponse response = await request.SendAsync("Hello, world!");
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.DataAsString);

JSON response handling:

using RestWrapper;

using RestRequest request = new RestRequest("https://api.example.com/items/123");
using RestResponse response = await request.SendAsync();

MyDto dto = response.DataFromJson<MyDto>();
Console.WriteLine(dto.Name);

Form data:

using RestWrapper;
using System.Net.Http;

using RestRequest request = new RestRequest("https://api.example.com/login", HttpMethod.Post);

Dictionary<string, string> form = new Dictionary<string, string>
{
    { "username", "alice" },
    { "password", "secret" }
};

using RestResponse response = await request.SendAsync(form);
Console.WriteLine(response.StatusCode);

Request Configuration

Headers and content type

using RestWrapper;
using System.Net.Http;

using RestRequest request = new RestRequest("https://api.example.com/items", HttpMethod.Post);
request.ContentType = "application/json; charset=utf-8";
request.Headers.Add("X-Correlation-Id", Guid.NewGuid().ToString());
request.Headers.Add("X-Tenant", "east");

using RestResponse response = await request.SendAsync("{\"name\":\"demo\"}");

Authorization

Basic auth:

using RestWrapper;

using RestRequest request = new RestRequest("https://api.example.com/secure");
request.Authorization.User = "alice";
request.Authorization.Password = "secret";

using RestResponse response = await request.SendAsync();

Bearer auth:

using RestWrapper;

using RestRequest request = new RestRequest("https://api.example.com/secure");
request.Authorization.BearerToken = "your-token";

using RestResponse response = await request.SendAsync();

Raw authorization header:

using RestWrapper;

using RestRequest request = new RestRequest("https://api.example.com/secure");
request.Authorization.Raw = "Custom scheme-value";

using RestResponse response = await request.SendAsync();

Streams

using RestWrapper;
using System.Net.Http;
using System.Text;

byte[] payload = Encoding.UTF8.GetBytes("streamed payload");
using MemoryStream stream = new MemoryStream(payload);

using RestRequest request = new RestRequest("https://api.example.com/upload", HttpMethod.Put);
request.ContentType = "text/plain";

using RestResponse response = await request.SendAsync(payload.Length, stream);
Console.WriteLine(response.StatusCode);

Response Handling

For regular responses, RestWrapper gives you multiple access patterns:

  • response.Data for the raw stream
  • response.DataAsBytes for the buffered byte array
  • response.DataAsString for UTF-8 string content
  • response.DataFromJson<T>() for JSON payloads

Example:

using RestWrapper;

using RestRequest request = new RestRequest("https://api.example.com/items/123");
using RestResponse response = await request.SendAsync();

Console.WriteLine(response.IsSuccessStatusCode);
Console.WriteLine(response.ContentType);
Console.WriteLine(response.ContentLength);
Console.WriteLine(response.DataAsString);

Timing metadata

Each RestResponse includes a Time property:

using RestWrapper;

using RestRequest request = new RestRequest("https://api.example.com/status");
using RestResponse response = await request.SendAsync();

Console.WriteLine("Start    : " + response.Time.Start);
Console.WriteLine("End      : " + response.Time.End);
Console.WriteLine("Total ms : " + response.Time.TotalMs);

Server-Sent Events

When the server returns text/event-stream, use ReadEventAsync() instead of Data, DataAsString, or DataFromJson<T>().

using RestWrapper;

using RestRequest request = new RestRequest("https://api.example.com/events");
using RestResponse response = await request.SendAsync();

while (true)
{
    ServerSentEvent evt = await response.ReadEventAsync();
    if (evt == null) break;

    Console.WriteLine($"[{evt.Event}] {evt.Data}");
}

ServerSentEvent exposes:

  • Id
  • Event
  • Data
  • Retry

Chunked Transfer

RestWrapper supports chunked request sending and chunked response reading.

using RestWrapper;
using System.Net.Http;

using RestRequest request = new RestRequest("https://api.example.com/chunked", HttpMethod.Post);
request.ChunkedTransfer = true;

await request.SendChunkAsync("chunk-1", false);
await request.SendChunkAsync("chunk-2", false);

using RestResponse response = await request.SendChunkAsync(Array.Empty<byte>(), true);

while (true)
{
    ChunkData chunk = await response.ReadChunkAsync();
    if (chunk == null) break;

    Console.WriteLine(System.Text.Encoding.UTF8.GetString(chunk.Data));

    if (chunk.IsFinal) break;
}

As with SSE, chunked responses are a specialized mode. Use ReadChunkAsync() instead of Data, DataAsString, DataAsBytes, or DataFromJson<T>().

Caller-Supplied HttpClient

If you already manage HttpClient instances through dependency injection or need custom handler behavior, you can provide your own HttpClient to RestRequest.

using RestWrapper;
using System.Net.Http;

using HttpClient client = new HttpClient();
using RestRequest request = new RestRequest(
    "https://api.example.com/resource",
    HttpMethod.Get,
    client);

using RestResponse response = await request.SendAsync();
Console.WriteLine(response.StatusCode);

This is useful for:

  • connection reuse
  • proxy settings
  • mTLS and client certificates
  • custom message handlers
  • centralized HttpClientFactory usage

Important behavior:

  • caller-supplied clients remain caller-owned
  • RestRequest will not dispose an external HttpClient
  • per-request headers and authorization are applied at the request-message level so shared clients do not leak state between requests

When you supply your own HttpClient, transport-level settings also become caller-owned. In that mode, do not use these RestRequest properties:

  • TimeoutMilliseconds
  • AllowAutoRedirect
  • IgnoreCertificateErrors
  • CertificateFilename
  • CertificatePassword

Configure those on your HttpClient / handler instead.

Custom Serialization

RestResponse.DataFromJson<T>() uses System.Text.Json by default, but you can replace the serializer:

using RestWrapper;

using RestRequest request = new RestRequest("https://api.example.com/items/123");
using RestResponse response = await request.SendAsync();
response.SerializationHelper = new MySerializer();

MyDto dto = response.DataFromJson<MyDto>();

MySerializer just needs to implement ISerializationHelper.

Test Projects

The repository includes both interactive and automated test hosts:

  • src/Test is the interactive console app
  • src/Test.Shared contains the shared Touchstone suites
  • src/Test.Automated is the console/CLI automation runner
  • src/Test.Xunit exposes the shared suite through dotnet test
  • src/Test.Nunit exposes the same shared suite through dotnet test

The current automated surface contains 120 shared cases covering:

  • internal and caller-supplied HttpClient flows
  • positive and negative transport behavior
  • shared-client header/auth isolation
  • SSE parsing, cancellation, and misuse guards
  • chunked read behavior, cancellation, and framing
  • response guards for regular vs streaming modes
  • serializer and helper utilities

Localhost Note

RestWrapper uses the platform HttpClient stack. When targeting localhost, some environments will try IPv6 loopback first. If your local service is only listening on IPv4, that can introduce a noticeable delay.

If you see this behavior, prefer 127.0.0.1 instead of localhost.

Changelog

See CHANGELOG.md for version history.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  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 is compatible.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 is compatible.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 is compatible.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (27)

Showing the top 5 NuGet packages that depend on RestWrapper:

Package Downloads
KvpbaseSDK

C# SDK for Kvpbase object storage platform

Komodo.Sdk

Client SDK in C# for Komodo. Please either install Komodo.Daemon to integrate search within your application, or Komodo.Server to run a standalone server if you wish to use this client SDK. Komodo is an information search, metadata, storage, and retrieval platform.

GoogleMapsClient

I needed a simple way to parse addresses and resolve coordinates to an address. Plug in a Google Maps API key and you're all set.

LiteGraph

LiteGraph is a property graph database with support for graph relationships, tags, labels, metadata, data, and vectors.

SendWithBrevo

A simple C# class library to help simplify sending emails using Brevo.

GitHub repositories (2)

Showing the top 2 popular GitHub repositories that depend on RestWrapper:

Repository Stars
dotnet/WatsonWebserver
Watson is the fastest, easiest way to build scalable RESTful web servers and services in C#.
litegraphdb/litegraph
Lightweight graph database with relational, vector, and MCP support, designed to power knowledge and artificial intelligence persistence and retrieval.
Version Downloads Last Updated
3.2.0 149 5/18/2026
3.1.8 8,661 10/4/2025
3.1.7 387 10/1/2025
3.1.6 778 9/19/2025
3.1.5 6,144 3/10/2025
3.1.4 6,294 1/22/2025
3.1.3 651 12/13/2024
3.1.2 5,648 12/10/2024
3.1.1 336 12/10/2024
3.1.0 757 12/2/2024
3.0.22 1,297 10/29/2024
3.0.21 4,694 8/27/2024
3.0.20 4,552 5/21/2024
3.0.19 4,292 3/27/2024
3.0.18 1,663 1/16/2024
3.0.17 6,104 11/25/2023
3.0.16 689 11/10/2023
3.0.15 656 11/10/2023
3.0.14 1,493 10/21/2023
Loading failed

Custom HttpClient injection support, safer shared-client request handling, and expanded automated test coverage.