DalSoft.RestClient 5.1.0

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

DalSoft .NET REST Client for all platforms

If you find this repo / package useful all I ask is you please star it ⭐

Do you or the company you work for benefit from the tools I build? <br /> If so please consider Becoming a Sponsor it would be greatly appreciated ❤️

Nuget StackOverflow Docs

For everything you need to know, please head over to https://restclient.dalsoft.io

👉 New Static Typing and Resource Expressions in 4.0

alt text

Just some of the things you can do with DalSoft.RestClient

Supported Platforms

RestClient targets .NET Standard 2.0 therefore supports Windows, Linux, Mac and Xamarin (iOS, Android and UWP).

Targets .NET Standard 2.0 and .NET 8.0 All versions of .NET Core / .NET 5+ supported All versions of legacy .NET Framework > 4.6.1 supported

Getting Started

Install via .NET CLI

> dotnet add package DalSoft.RestClient

Install via NuGet

PM> Install-Package DalSoft.RestClient

Example calling a REST API

You start by new'ing up the RestClient and passing in the base uri for your RESTful API.

For example if your wanted to perform a GET on https://jsonplaceholder.typicode.com/users/1 you would do the following:

Static Typed Rest Client

For the Static typed Rest Client just pass a string representing the resource you want access to the Resource method, and then call the HTTP method you want to use.

var client = new RestClient("https://jsonplaceholder.typicode.com");

User user = await client.Resource("users/1").Get();
   
Console.WriteLine(user.Name);

Dynamicaly Typed Rest Client

For the Dynamicaly typed Rest Client chain members that would make up the resource you want to access - ending with the HTTP method you want to use.

dynamic client = new RestClient("https://jsonplaceholder.typicode.com");

var user = await client.Users(1).Get();
   
Console.WriteLine(user.name);

Note all HTTP methods are async

Recent Releases

About

RestClient is a very lightweight wrapper around System.Net.HttpClient that uses the dynamic features of .NET 4 to provide a fluent way of accessing RESTFul API's, making it trivial to create REST requests using a lot less code.

Originally created to remove the boilerplate code involved in making REST requests using code that is testable. I know there are a couple of REST clients out there but I wanted the syntax to look a particular way with minimal fuss.

RestClient is biased towards posting and returning JSON - if you don't provide Accept and Content-Type headers then they are set to application/json by default See Working with non JSON content.

Version 5.1 Typed Clients

Register a typed client the same way you would with AddHttpClient<TClient>() and take IRestClient in the constructor - no HttpClientWrapper plumbing:

services.AddRestClient<GitHubClient>("https://api.github.com", new Headers(new { UserAgent = "MyClient" }))
    .UseRetryHandler(); // Any Use*Handler applies to this client only

public class GitHubClient
{
    private readonly IRestClient _restClient;

    public GitHubClient(IRestClient restClient) => _restClient = restClient;

    public Task<List<Repository>> GetRepositories(string user) =>
        _restClient.Resource($"users/{user}/repos").Get<List<Repository>>();
}

AddRestClient<TClient, TImplementation>() registers an interface with its implementation. Typed clients are transient (like AddHttpClient<TClient>()), can take other dependencies in their constructor, and are unit tested with UseUnitTestHandler() like everything else. Outside of DI just use new RestClient("https://api.github.com", new Headers(new { UserAgent = "MyClient" })).

Version 5.1 MCP (Model Context Protocol)

UseMcpHandler() turns a RestClient into an MCP client using the Streamable HTTP transport. Point the base uri at the MCP endpoint and go - the session is initialized lazily on the first call, Mcp-Session-Id / MCP-Protocol-Version headers are tracked for you, SSE responses are read until the JSON-RPC response arrives, and the JSON-RPC envelope is unwrapped so you just get the result:

IRestClient mcp = new RestClient("https://example.com/mcp", new Config().UseMcpHandler());

var tools = await mcp.ListTools();
var result = await mcp.CallTool("echo", new { message = "hello" });
string text = result.content[0].text;

// Or strongly typed
var typed = await mcp.CallTool<CallToolResult>("echo", new { message = "hello" });

// Tools usually return JSON as text, CallToolJson parses it (or uses structuredContent) and throws McpException on isError
var quotes = await mcp.CallToolJson("get_quote", new { symbols = new[] { "MSFT" } });
Console.WriteLine(quotes[0].regularMarketPrice); // or CallToolJson<Quote[]>(...) for strongly typed

// Anything else is one line
var templates = await mcp.McpRequest("resources/templates/list");

Helpers: Ping(), ListTools(), CallTool(), CallToolJson(), ListResources(), ReadResource(), ListPrompts(), GetPrompt() and McpRequest(method, params), all with <TReturns> twins. They are extension methods on IRestClient, so declare the variable as IRestClient rather than dynamic. JSON-RPC errors throw McpException with Code, Message and Data. Server notifications sent on a response stream (for example notifications/progress) are surfaced via McpHandlerOptions.OnNotification.

With DI the session is shared across IHttpClientFactory handler rotation, and combines with typed clients:

services.AddRestClient<MyMcpClient>("https://example.com/mcp")
    .UseMcpHandler(new McpHandlerOptions { ClientName = "MyApp", ClientVersion = "1.0" });

Notes: authentication is whatever you already use (Authorization(), headers or your own handler). Long running tool calls are bound by Config.Timeout (100 seconds by default). Put UseRetryHandler() after UseMcpHandler() if you use both, otherwise a retry would replay the tool call. Not in 5.1: the client side GET listening stream, Last-Event-ID resume, sampling/elicitation (answered with -32601 Method not found) and the legacy 2024-11-05 HTTP+SSE transport.

Version 5.0 Breaking Changes

From version 5.0 RestClient uses System.Text.Json to serialize requests and deserialize responses - with stock System.Text.Json behaviour, so [JsonPropertyName] attributes are honoured and property matching is case sensitive. The only leniency added on top of the stock defaults is that trailing commas and comments are accepted when reading, because real world systems are less than perfect.

To customise serialization pass your JsonSerializerOptions:

var config = new Config().SetJsonSerializerOptions(new JsonSerializerOptions(JsonSerializerDefaults.Web)); 

If you need the legacy Json.NET behaviour ([JsonProperty] attributes, JsonSerializerSettings etc.) opt in to the fallback - this restores the 4.x behaviour exactly:

var config = new Config().UseNewtonsoftJson(); // optionally takes your JsonSerializerSettings

SetJsonSerializerSettings and Config.JsonSerializerSettings have been removed - use UseNewtonsoftJson(jsonSerializerSettings) instead. Note that failed typed casts now throw System.Text.Json.JsonException unless you opt in to Json.NET.

Performance

Near-native performance - typed requests allocate the same as using HttpClient and System.Text.Json by hand, and several times leaner than RestSharp.

Version 5.0 had a performance pass guided by BenchmarkDotNet - requests and responses are serialized straight to and from utf-8 bytes skipping intermediate strings, the JSON DOM is only built if you use dynamic access (typed casts skip it entirely), and arrays are wrapped lazily.

Before and after the performance pass, 10,000 item JSON payload, in process (no network), .NET 8:

Scenario 4.x 5.0
Typed response List<User> 22.1 ms / 9.87 MB 13.5 ms / 5.10 MB
Dynamic access result[0].id 8.86 ms / 6.59 MB 5.28 ms / 5.46 MB
Typed response single object 5.98 µs / 4.59 KB 3.66 µs / 2.95 KB
POST List<User> body 5.83 ms / 3.40 MB 3.69 ms / 1.13 MB

Measured against using HttpClient and System.Text.Json by hand, POST request bodies and typed responses now allocate about the same (1.0x), down from 3.0x and 3.5x respectively.

Real world comparison

A real GET request to the GitHub API (https://api.github.com/repos/DalSoft/DalSoft.RestClient) deserialized to a typed model, compared to native HttpClient and other popular REST clients, .NET 8:

Client Median Mean Allocated Alloc Ratio
HttpClient + GetFromJsonAsync 51.01 ms 49.64 ms 11.38 KB 1.00x
DalSoft.RestClient 5.0 41.38 ms 40.76 ms 23.24 KB 2.04x
RestSharp 114.0 45.45 ms 45.57 ms 135.74 KB 11.93x
Flurl.Http 4.0.2 19.64 ms 22.83 ms 19.79 KB 1.74x
Refit 15.0 39.55 ms 42.98 ms 17.80 KB 1.56x
RestClient.Net 7.2.1 * 51.07 ms 91.76 ms 15.27 KB 1.34x

Time over a real network is dominated by latency so every client lands within noise of native HttpClient - don't read the time column as a ranking, the differences (including where a client appears faster than native HttpClient) are statistical noise. The allocations column is what shows the overhead each library adds per request. DalSoft.RestClient stays close to native and the lightweight clients while giving you a full dynamic API, and allocates about 6x less than RestSharp.

* RestClient.Net 7 doesn't deserialize for you - you supply your own System.Text.Json delegate, so its numbers exclude the library-side JSON handling every other row includes.

To run the benchmarks yourself: dotnet run -c Release in the DalSoft.RestClient.Benchmarks project. The real world benchmark makes around 50 requests - GitHub allows 60 unauthenticated requests an hour, set the GITHUB_TOKEN environment variable to raise the limit.

Standing on the Shoulders of Giants

DalSoft.RestClient is built using the following great open source projects:

DalSoft.RestClient is inspired by and gives credit to:

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  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. 
.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 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  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 (3)

Showing the top 3 NuGet packages that depend on DalSoft.RestClient:

Package Downloads
DalSoft.RestClient.Testing

Use DalSoft.RestClient with ASP.NET Core In-Memory Test Server for integration tests.

RoomerSDK

SDK for Roomer API

RamApidotnet

Package Description

GitHub repositories (1)

Showing the top 1 popular GitHub repositories that depend on DalSoft.RestClient:

Repository Stars
kitamstudios/rust-analyzer.vs
Rust language support for Visual Studio 2022
Version Downloads Last Updated
5.1.0 57 8/21/2026
5.0.0 301 8/8/2026
4.4.2 43,113 9/2/2024
4.4.1 71,127 12/2/2021
4.4.0 30,964 12/18/2020
4.3.0 2,994 11/25/2020
4.2.1 8,219 9/24/2020
4.2.0 25,109 10/26/2019
4.1.0 14,034 8/24/2019
4.0.0 2,919 8/4/2019
3.3.2 20,459 12/3/2018
3.3.1 3,186 10/29/2018
3.3.0 5,225 7/11/2018
3.2.3 2,702 4/25/2018
3.2.2 49,594 5/4/2017
3.1.1 2,415 4/23/2017
3.1.0 2,375 4/20/2017
3.0.3 3,191 2/27/2017
Loading failed

5.1.0 - MCP (Model Context Protocol) and Typed Clients.

     McpHandler - call MCP servers over the Streamable HTTP transport with Config.UseMcpHandler() or AddRestClient(...).UseMcpHandler(). The JSON-RPC envelope, lazy session initialization, Mcp-Session-Id / MCP-Protocol-Version headers, SSE response streams (with OnNotification for progress) and re-initialization on 404 are all handled for you, and the JSON-RPC result is unwrapped so the response is just the result. JSON-RPC errors throw McpException.

     IRestClient MCP helpers - Ping, ListTools, CallTool, ListResources, ReadResource, ListPrompts, GetPrompt and McpRequest, each with a strongly typed twin. CallToolJson returns a tool's JSON result (structuredContent or the text content parsed as JSON) dynamically typed like any other RestClient response, or strongly typed via CallToolJson<T>, and throws McpException when the tool returns isError.

     Typed clients - AddRestClient<TClient>() and AddRestClient<TClient, TImplementation>() register a typed client with a configured IRestClient injected into its constructor, mirroring AddHttpClient<TClient>(). No more wrapping HttpClient in HttpClientWrapper yourself.

     Breaking changes:
     - TwitterHandler and UseTwitterHandler() have been removed, the Twitter API v1.1 it targeted is no longer available.

     5.0.0 - System.Text.Json is now the default serializer with stock System.Text.Json behaviour (plus trailing commas and comments accepted when reading, because real world systems are less than perfect).

     Big performance improvements - requests and responses are serialized straight to and from utf-8 bytes skipping intermediate strings, the JSON DOM is only built if you use dynamic access (typed casts skip it entirely), arrays are wrapped lazily, and the request pipeline allocates far less. Request bodies and typed responses now allocate about the same as using HttpClient and System.Text.Json by hand. Also now multi targets netstandard2.0 and net8.0.

     Breaking changes:
     - [JsonPropertyName] attributes are honoured and property matching is case sensitive, [JsonProperty] attributes are no longer honoured by default.
     - Config.JsonSerializerSettings and SetJsonSerializerSettings have been removed, use SetJsonSerializerOptions(JsonSerializerOptions) to customise System.Text.Json.
     - Failed typed casts now throw System.Text.Json.JsonException.
     - To restore the legacy Json.NET 4.x behaviour exactly call UseNewtonsoftJson() optionally passing your JsonSerializerSettings.