Nethereum.Util.Rest Nethereum Utility Library providing a generic interface and a simple implementation of a Rest client api
$ dotnet add package Nethereum.Util.RestGeneric REST client abstraction and implementation for HTTP API interactions with JSON serialization support.
Nethereum.Util.Rest provides a lightweight wrapper around HttpClient for making REST API calls with automatic JSON serialization/deserialization. It's designed to simplify HTTP communication in Nethereum components and user applications.
Key Features:
dotnet add package Nethereum.Util.Rest
Or via Package Manager Console:
Install-Package Nethereum.Util.Rest
External:
Nethereum:
The IRestHttpHelper interface provides a generic abstraction for REST operations:
public interface IRestHttpHelper
{
Task<T> GetAsync<T>(string path, Dictionary<string, string> headers = null);
Task<TResponse> PostAsync<TResponse, TRequest>(string path, TRequest request, Dictionary<string, string> headers = null);
Task<TResponse> PutAsync<TResponse, TRequest>(string path, TRequest request, Dictionary<string, string> headers = null);
Task DeleteAsync(string path, Dictionary<string, string> headers = null);
Task<TResponse> PostMultipartAsync<TResponse>(string path, MultipartFormDataRequest request, Dictionary<string, string> headers = null);
}
Concrete implementation that wraps HttpClient and handles JSON serialization automatically.
Extension methods for HttpClient with built-in Bearer token authentication support (NET 5.0+).
System.Text.Json for better performanceNewtonsoft.Json for compatibilityusing Nethereum.Util.Rest;
using System.Net.Http;
// Create REST helper
var httpClient = new HttpClient();
var restHelper = new RestHttpHelper(httpClient);
// Make a GET request
var data = await restHelper.GetAsync<MyDataModel>("https://api.example.com/data");
// Make a POST request
var response = await restHelper.PostAsync<ResponseModel, RequestModel>(
"https://api.example.com/submit",
new RequestModel { Value = "test" }
);
using Nethereum.Util.Rest;
using System.Collections.Generic;
using System.Net.Http;
// Create REST helper
var restHelper = new RestHttpHelper(new HttpClient());
// Define custom headers
var headers = new Dictionary<string, string>
{
{ "accept", "application/json" }
};
// Make GET request
var result = await restHelper.GetAsync<ApiResponse>(
"https://api.example.com/v1/data",
headers
);
public class ApiResponse
{
public string Status { get; set; }
public object Data { get; set; }
}
using Nethereum.Util.Rest;
using System.Net.Http;
// Service class using dependency injection
public class BeaconApiClient
{
private readonly IRestHttpHelper _restHelper;
public string BaseUrl { get; }
// Constructor with HttpClient
public BeaconApiClient(string baseUrl, HttpClient httpClient = null)
{
BaseUrl = baseUrl.TrimEnd('/');
_restHelper = new RestHttpHelper(httpClient ?? new HttpClient());
}
// Constructor with IRestHttpHelper (for testing)
public BeaconApiClient(string baseUrl, IRestHttpHelper restHelper)
{
BaseUrl = baseUrl.TrimEnd('/');
_restHelper = restHelper;
}
// Example method
public async Task<BootstrapResponse> GetBootstrapAsync(string blockRoot)
{
var url = $"{BaseUrl}/eth/v1/beacon/light_client/bootstrap/{blockRoot}";
return await _restHelper.GetAsync<BootstrapResponse>(url);
}
}
using Nethereum.Util.Rest;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
public class FourByteDirectoryService
{
public const string BaseUrl = "https://www.4byte.directory";
private IRestHttpHelper _restHttpHelper;
public FourByteDirectoryService()
{
_restHttpHelper = new RestHttpHelper(new HttpClient());
}
public FourByteDirectoryService(IRestHttpHelper restHttpHelper)
{
_restHttpHelper = restHttpHelper;
}
// Get function signature by hex signature (e.g., "0xa9059cbb")
public Task<FourByteDirectoryResponse> GetFunctionSignatureByHexSignatureAsync(
string hexSignature)
{
var url = $"{BaseUrl}/api/v1/signatures/?hex_signature={hexSignature}";
return GetDataAsync<FourByteDirectoryResponse>(url);
}
// Get function signature by text (e.g., "transfer(address,uint256)")
public Task<FourByteDirectoryResponse> GetFunctionSignatureByTextSignatureAsync(
string textSignature)
{
var url = $"{BaseUrl}/api/v1/signatures/?text_signature={textSignature}";
return GetDataAsync<FourByteDirectoryResponse>(url);
}
private async Task<T> GetDataAsync<T>(string url)
{
var headers = new Dictionary<string, string>
{
{ "accept", "application/json" }
};
return await _restHttpHelper.GetAsync<T>(url, headers);
}
}
using Nethereum.Util.Rest;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
public class SourcifyApiService
{
public const string BaseUrl = "https://sourcify.dev/server/";
public const string BaseUrlMeta = "https://repo.sourcify.dev/";
private IRestHttpHelper restHttpHelper;
public SourcifyApiService()
{
restHttpHelper = new RestHttpHelper(new HttpClient());
}
public SourcifyApiService(HttpClient httpClient)
{
restHttpHelper = new RestHttpHelper(httpClient);
}
// Get compilation metadata for verified contract
public Task<CompilationMetadata> GetCompilationMetadataAsync(
long chain,
string address,
bool fullMatch = true)
{
var matchType = fullMatch ? "full_match" : "partial_match";
var url = $"{BaseUrlMeta}/contracts/{matchType}/{chain}/{address}/metadata.json";
return GetDataAsync<CompilationMetadata>(url);
}
// Get source files for verified contract
public Task<List<SourcifyContentFile>> GetSourceFilesFullMatchAsync(
long chain,
string address)
{
var url = $"{BaseUrl}/files/{chain}/{address}";
return GetDataAsync<List<SourcifyContentFile>>(url);
}
private Task<T> GetDataAsync<T>(string url)
{
var headers = new Dictionary<string, string>
{
{ "accept", "application/json" }
};
return restHttpHelper.GetAsync<T>(url, headers);
}
}
using Nethereum.Util.Rest;
using System.Net.Http;
var restHelper = new RestHttpHelper(new HttpClient());
// Define request and response models
public class CreateUserRequest
{
public string Username { get; set; }
public string Email { get; set; }
}
public class CreateUserResponse
{
public int UserId { get; set; }
public string Status { get; set; }
}
// Make POST request
var request = new CreateUserRequest
{
Username = "alice",
Email = "alice@example.com"
};
var response = await restHelper.PostAsync<CreateUserResponse, CreateUserRequest>(
"https://api.example.com/users",
request
);
Console.WriteLine($"Created user ID: {response.UserId}");
using Nethereum.Util.Rest;
using System.Collections.Generic;
using System.Net.Http;
var restHelper = new RestHttpHelper(new HttpClient());
public class UpdateProfileRequest
{
public string DisplayName { get; set; }
public string Bio { get; set; }
}
public class UpdateProfileResponse
{
public bool Success { get; set; }
public string Message { get; set; }
}
// Update with custom headers
var headers = new Dictionary<string, string>
{
{ "X-Api-Version", "2.0" }
};
var updateRequest = new UpdateProfileRequest
{
DisplayName = "Alice Smith",
Bio = "Blockchain developer"
};
var result = await restHelper.PutAsync<UpdateProfileResponse, UpdateProfileRequest>(
"https://api.example.com/profile/123",
updateRequest,
headers
);
using Nethereum.Util.Rest;
using System.Collections.Generic;
using System.Net.Http;
var restHelper = new RestHttpHelper(new HttpClient());
// Delete with authentication header
var headers = new Dictionary<string, string>
{
{ "Authorization", "Bearer YOUR_TOKEN_HERE" }
};
await restHelper.DeleteAsync(
"https://api.example.com/items/456",
headers
);
Console.WriteLine("Item deleted successfully");
#if NET5_0_OR_GREATER
using Nethereum.Util.Rest;
using System.Net.Http;
var httpClient = new HttpClient();
string bearerToken = "your-jwt-token";
// GET with Bearer token
var userData = await httpClient.GetAsync<UserProfile>(
"https://api.example.com/user/profile",
bearerToken
);
// POST with Bearer token
var createData = new { name = "New Item", value = 100 };
var createResponse = await httpClient.PostAsync<CreateResponse>(
"https://api.example.com/items",
createData,
bearerToken
);
// PUT with Bearer token
var updateData = new { value = 200 };
var updateResponse = await httpClient.PutAsync<UpdateResponse>(
"https://api.example.com/items/123",
updateData,
bearerToken
);
// DELETE with Bearer token (returns int status)
var deleteStatus = await httpClient.DeleteAsync(
"https://api.example.com/items/123",
bearerToken
);
#endif
using Nethereum.Util.Rest;
using System.Collections.Generic;
using System.Net.Http;
var restHelper = new RestHttpHelper(new HttpClient());
// Create multipart request
var multipartRequest = new MultipartFormDataRequest
{
Fields = new List<MultipartField>
{
new MultipartField { Name = "title", Value = "My Contract" },
new MultipartField { Name = "network", Value = "mainnet" }
},
Files = new List<MultipartFile>
{
new MultipartFile
{
FieldName = "file",
FileName = "Token.sol",
Content = "pragma solidity ^0.8.0; contract Token { ... }",
ContentType = "text/plain"
}
}
};
// Add authorization header
var headers = new Dictionary<string, string>
{
{ "Authorization", "Bearer YOUR_TOKEN" }
};
// Upload file
var uploadResponse = await restHelper.PostMultipartAsync<UploadResponse>(
"https://api.example.com/upload",
multipartRequest,
headers
);
Console.WriteLine($"Upload status: {uploadResponse.Status}");
public class UploadResponse
{
public string Status { get; set; }
public string FileId { get; set; }
}
Generic REST client interface.
public interface IRestHttpHelper
{
// GET request with JSON deserialization
Task<T> GetAsync<T>(string path, Dictionary<string, string> headers = null);
// POST request with JSON serialization/deserialization
Task<TResponse> PostAsync<TResponse, TRequest>(
string path,
TRequest request,
Dictionary<string, string> headers = null);
// PUT request with JSON serialization/deserialization
Task<TResponse> PutAsync<TResponse, TRequest>(
string path,
TRequest request,
Dictionary<string, string> headers = null);
// DELETE request
Task DeleteAsync(string path, Dictionary<string, string> headers = null);
// POST multipart form data (file uploads)
Task<TResponse> PostMultipartAsync<TResponse>(
string path,
MultipartFormDataRequest request,
Dictionary<string, string> headers = null);
}
Concrete implementation of IRestHttpHelper.
public class RestHttpHelper : IRestHttpHelper
{
// Constructor - optionally provide HttpClient
public RestHttpHelper(HttpClient httpClient = null);
// Implements all IRestHttpHelper methods
// Throws Exception on non-success status codes
}
Extension methods for HttpClient with Bearer token authentication.
public static class HttpClientExtensions
{
// GET with Bearer token
public static Task<T> GetAsync<T>(
this HttpClient httpClient,
string url,
string token);
// POST with Bearer token and response
public static Task<T> PostAsync<T>(
this HttpClient httpClient,
string url,
object data,
string token);
// POST with Bearer token returning HttpResponseMessage
public static Task<HttpResponseMessage> PostAsync(
this HttpClient httpClient,
string url,
object data,
string token);
// PUT with Bearer token
public static Task<T> PutAsync<T>(
this HttpClient httpClient,
string url,
object data,
string token);
// DELETE with Bearer token
public static Task<int> DeleteAsync(
this HttpClient httpClient,
string url,
string token);
}
Container for multipart form data uploads.
public class MultipartFormDataRequest
{
public List<MultipartField> Fields { get; set; }
public List<MultipartFile> Files { get; set; }
}
public class MultipartField
{
public string Name { get; set; }
public string Value { get; set; }
}
public class MultipartFile
{
public string FieldName { get; set; } // Default: "file"
public string FileName { get; set; } // e.g., "Token.sol"
public string Content { get; set; } // File content as string
public string ContentType { get; set; } // Default: "text/plain"
}
All methods throw Exception on non-success HTTP status codes:
try
{
var data = await restHelper.GetAsync<MyData>("https://api.example.com/data");
}
catch (Exception ex)
{
// ex.Message contains: "Error: {StatusCode}, {ResponseBody}, {Headers}"
Console.WriteLine($"API error: {ex.Message}");
}
Best Practice: Reuse HttpClient instances to avoid socket exhaustion.
// WRONG - creates new HttpClient for every request
public Task<T> GetDataAsync<T>(string url)
{
var helper = new RestHttpHelper(new HttpClient()); // Don't do this!
return helper.GetAsync<T>(url);
}
// CORRECT - reuse HttpClient
private readonly IRestHttpHelper _restHelper;
public MyService()
{
var httpClient = new HttpClient(); // Create once
_restHelper = new RestHttpHelper(httpClient);
}
Even Better: Use HttpClientFactory in ASP.NET Core:
// Startup.cs or Program.cs
services.AddHttpClient();
// Your service
public class MyService
{
private readonly IRestHttpHelper _restHelper;
public MyService(IHttpClientFactory httpClientFactory)
{
var httpClient = httpClientFactory.CreateClient();
_restHelper = new RestHttpHelper(httpClient);
}
}
The package automatically uses the best serializer for your framework:
System.Text.Json (faster, lower memory)Newtonsoft.Json (compatibility)This is transparent - you don't need to change your code.
HttpClientExtensions use case-insensitive JSON deserialization:
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
This allows matching API responses with different casing conventions.
RestHttpHelper is thread-safe when using a shared HttpClient (which is thread-safe). You can safely use a single instance across multiple threads.
This package is part of the Nethereum project and follows the same MIT license.