JsonRpc Rpc Client Nethereum provider
$ dotnet add package Nethereum.JsonRpc.RpcClientProduction-ready HTTP/HTTPS JSON-RPC client for Ethereum node communication.
Nethereum.JsonRpc.RpcClient provides the standard HTTP/HTTPS transport implementation for communicating with Ethereum nodes via JSON-RPC. This is the most commonly used RPC client in Nethereum, offering robust connection management, automatic retries, authentication support, and production-tested reliability.
Key Features:
Use Cases:
dotnet add package Nethereum.JsonRpc.RpcClient
This is typically the default RPC client used by Nethereum.Web3:
dotnet add package Nethereum.Web3
Nethereum:
Framework:
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth;
// Connect to local node
var client = new RpcClient(new Uri("http://localhost:8545"));
// Use with RPC services
var ethBlockNumber = new EthBlockNumber(client);
var blockNumber = await ethBlockNumber.SendRequestAsync();
Console.WriteLine($"Current block: {blockNumber.Value}");
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth;
using Nethereum.Hex.HexTypes;
// Local Geth/Erigon/Besu node
var client = new RpcClient(new Uri("http://localhost:8545"));
// Infura
var infuraClient = new RpcClient(
new Uri("https://mainnet.infura.io/v3/YOUR_PROJECT_ID")
);
// Alchemy
var alchemyClient = new RpcClient(
new Uri("https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY")
);
// Use with any RPC service
var ethChainId = new EthChainId(client);
HexBigInteger chainId = await ethChainId.SendRequestAsync();
Console.WriteLine($"Chain ID: {chainId.Value}");
// Output: Chain ID: 1 (mainnet)
using Nethereum.JsonRpc.Client;
using System.Net.Http.Headers;
using System.Text;
// Option 1: URL-based authentication (simplest)
var client = new RpcClient(
new Uri("http://username:password@localhost:8545")
);
// Option 2: Explicit AuthenticationHeaderValue
var credentials = Convert.ToBase64String(
Encoding.UTF8.GetBytes("admin:secretpassword")
);
var authHeader = new AuthenticationHeaderValue("Basic", credentials);
var authenticatedClient = new RpcClient(
new Uri("http://localhost:8545"),
authHeaderValue: authHeader
);
// Use authenticated client
var ethAccounts = new EthAccounts(authenticatedClient);
var accounts = await ethAccounts.SendRequestAsync();
Console.WriteLine($"Accounts: {string.Join(", ", accounts)}");
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth;
var client = new RpcClient(new Uri("http://localhost:8545"));
// Default timeout is 120 seconds (2 minutes)
Console.WriteLine($"Default timeout: {client.ConnectionTimeout.TotalSeconds}s");
// Set custom timeout for slow networks
client.ConnectionTimeout = TimeSpan.FromSeconds(30);
try
{
var ethGasPrice = new EthGasPrice(client);
var gasPrice = await ethGasPrice.SendRequestAsync();
Console.WriteLine($"Gas price: {gasPrice.Value} wei");
}
catch (RpcClientTimeoutException ex)
{
Console.WriteLine($"Request timed out after 30 seconds: {ex.Message}");
}
using Nethereum.JsonRpc.Client;
using System.Net.Http;
// Create custom HttpClient with specific settings
var httpClient = new HttpClient(new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(15),
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(10),
MaxConnectionsPerServer = 50,
EnableMultipleHttp2Connections = true
})
{
Timeout = TimeSpan.FromSeconds(60)
};
// Create RpcClient with custom HttpClient
var client = new RpcClient(
new Uri("http://localhost:8545"),
httpClient: httpClient
);
var ethBlockNumber = new EthBlockNumber(client);
var blockNumber = await ethBlockNumber.SendRequestAsync();
Console.WriteLine($"Block: {blockNumber.Value}");
using Nethereum.JsonRpc.Client;
using System.Net;
using System.Net.Http;
// Configure proxy
var handler = new HttpClientHandler
{
Proxy = new WebProxy("http://proxy.example.com:8080")
{
Credentials = new NetworkCredential("proxyuser", "proxypass")
},
UseProxy = true,
MaxConnectionsPerServer = 20
};
// Create client with proxy handler
var client = new RpcClient(
new Uri("http://localhost:8545"),
httpClientHandler: handler
);
var ethChainId = new EthChainId(client);
var chainId = await ethChainId.SendRequestAsync();
Console.WriteLine($"Chain ID (via proxy): {chainId.Value}");
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth.DTOs;
using System.Threading.Tasks;
var client = new RpcClient(new Uri("http://localhost:8545"));
// RpcClient is thread-safe - can handle concurrent requests
var tasks = new List<Task>
{
Task.Run(async () =>
{
var ethBlockNumber = new EthBlockNumber(client);
var block = await ethBlockNumber.SendRequestAsync();
Console.WriteLine($"Task 1 - Block: {block.Value}");
}),
Task.Run(async () =>
{
var ethGasPrice = new EthGasPrice(client);
var gasPrice = await ethGasPrice.SendRequestAsync();
Console.WriteLine($"Task 2 - Gas Price: {gasPrice.Value}");
}),
Task.Run(async () =>
{
var ethChainId = new EthChainId(client);
var chainId = await ethChainId.SendRequestAsync();
Console.WriteLine($"Task 3 - Chain ID: {chainId.Value}");
})
};
await Task.WhenAll(tasks);
Console.WriteLine("All requests completed successfully");
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth;
using Polly;
var client = new RpcClient(new Uri("http://localhost:8545"));
client.ConnectionTimeout = TimeSpan.FromSeconds(10);
// Define retry policy with Polly
var retryPolicy = Policy
.Handle<RpcClientTimeoutException>()
.Or<RpcClientUnknownException>()
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)),
onRetry: (exception, timeSpan, retryCount, context) =>
{
Console.WriteLine($"Retry {retryCount} after {timeSpan.TotalSeconds}s due to: {exception.Message}");
}
);
try
{
var blockNumber = await retryPolicy.ExecuteAsync(async () =>
{
var ethBlockNumber = new EthBlockNumber(client);
return await ethBlockNumber.SendRequestAsync();
});
Console.WriteLine($"Success! Block: {blockNumber.Value}");
}
catch (RpcResponseException ex)
{
Console.WriteLine($"RPC Error {ex.RpcError.Code}: {ex.RpcError.Message}");
}
catch (RpcClientTimeoutException ex)
{
Console.WriteLine($"Timeout after retries: {ex.Message}");
}
catch (RpcClientUnknownException ex)
{
Console.WriteLine($"Network error: {ex.Message}");
}
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth;
public class LoadBalancedRpcClient
{
private readonly List<RpcClient> _clients;
private int _currentIndex = 0;
private readonly object _lock = new object();
public LoadBalancedRpcClient(params string[] nodeUrls)
{
_clients = nodeUrls.Select(url => new RpcClient(new Uri(url))).ToList();
}
public RpcClient GetNextClient()
{
lock (_lock)
{
var client = _clients[_currentIndex];
_currentIndex = (_currentIndex + 1) % _clients.Count;
return client;
}
}
}
// Usage
var loadBalancer = new LoadBalancedRpcClient(
"http://node1.example.com:8545",
"http://node2.example.com:8545",
"http://node3.example.com:8545"
);
// Round-robin requests
for (int i = 0; i < 10; i++)
{
var client = loadBalancer.GetNextClient();
var ethBlockNumber = new EthBlockNumber(client);
var block = await ethBlockNumber.SendRequestAsync();
Console.WriteLine($"Request {i + 1} - Block: {block.Value}");
}
using Nethereum.Web3;
using Nethereum.JsonRpc.Client;
// Option 1: Web3 creates RpcClient internally (simplest)
var web3 = new Web3("https://mainnet.infura.io/v3/YOUR_PROJECT_ID");
// Option 2: Create custom RpcClient first
var client = new RpcClient(new Uri("http://localhost:8545"));
client.ConnectionTimeout = TimeSpan.FromSeconds(60);
var web3WithCustomClient = new Web3(client);
// Use Web3 normally
var balance = await web3WithCustomClient.Eth.GetBalance.SendRequestAsync("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb");
Console.WriteLine($"Balance: {Web3.Convert.FromWei(balance)} ETH");
var blockNumber = await web3WithCustomClient.Eth.Blocks.GetBlockNumber.SendRequestAsync();
Console.WriteLine($"Block: {blockNumber.Value}");
// Basic constructor
public RpcClient(Uri baseUrl,
AuthenticationHeaderValue authHeaderValue = null,
JsonSerializerSettings jsonSerializerSettings = null,
HttpClientHandler httpClientHandler = null,
ILogger log = null)
// With custom HttpClient
public RpcClient(Uri baseUrl,
HttpClient httpClient,
AuthenticationHeaderValue authHeaderValue = null,
JsonSerializerSettings jsonSerializerSettings = null,
ILogger log = null)
public static int MaximumConnectionsPerServer { get; set; } = 20;
public TimeSpan ConnectionTimeout { get; set; } // Default: 120 seconds
public RequestInterceptor OverridingRequestInterceptor { get; set; }
Task<T> SendRequestAsync<T>(RpcRequest request, string route = null);
Task<T> SendRequestAsync<T>(string method, string route = null, params object[] paramList);
Task<RpcRequestResponseBatch> SendBatchRequestAsync(RpcRequestResponseBatch batch);
Task<RpcResponseMessage> SendAsync(RpcRequestMessage request, string route = null);
HttpClient Rotation:
MaximumConnectionsPerServer)Best Practices:
| Operation | Latency | Notes |
|---|---|---|
| Local node | 1-10ms | Localhost Geth/Erigon |
| Cloud provider | 50-200ms | Infura, Alchemy, QuickNode |
| Slow network | 200-500ms | High latency regions |
Optimization Tips:
EnableMultipleHttp2ConnectionsMaxConnectionsPerServer for high throughput| Exception | Cause | Retry? |
|---|---|---|
| RpcClientTimeoutException | Request exceeded ConnectionTimeout | Yes (with backoff) |
| RpcClientUnknownException | Network/HTTP errors | Yes (transient) |
| RpcResponseException | JSON-RPC error from node | Depends on error code |
| HttpRequestException | DNS, connection failures | Yes (with backoff) |
Supports HTTP Basic Authentication:
http://user:pass@localhost:8545AuthenticationHeaderValue("Basic", base64Credentials)Uses Newtonsoft.Json with default settings optimized for Ethereum:
0x hex prefixesFor System.Text.Json, use Nethereum.JsonRpc.SystemTextJsonRpcClient instead.
Supports Microsoft.Extensions.Logging:
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var logger = loggerFactory.CreateLogger<RpcClient>();
var client = new RpcClient(
new Uri("http://localhost:8545"),
log: logger
);
Logs include:
| Provider | URL Format | Notes |
|---|---|---|
| Infura | https://mainnet.infura.io/v3/PROJECT_ID | Free tier available |
| Alchemy | https://eth-mainnet.g.alchemy.com/v2/API_KEY | Enhanced APIs |
| QuickNode | https://your-endpoint.quiknode.pro/token/ | Global network |
| Local Geth | http://localhost:8545 | Full node |
| Local Erigon | http://localhost:8545 | Archive node |