Ethereum

Ethereum

C#

Nethereum is the de-facto way to reach Ethereum from .NET. It targets .NET Standard 2.0 and up, so the same code talks to chain 1 from a console tool, an ASP.NET Core API, a Blazor front end, a Xamarin app, or a Unity3D game. One dotnet add package Nethereum.Web3 pulls in the JSON-RPC client, ABI encoder, account handling, and the wei/ether conversion helpers you need to query a balance or sign a transaction against https://ethereum.therpc.io/YOUR_API_KEY.

Because Nethereum sits on .NET Standard 2.0+, a single dependency covers Unity3D, Xamarin, ASP.NET Core, and Blazor without per-platform forks. Install it from NuGet with dotnet add package Nethereum.Web3 and you are ready to point at Ethereum mainnet.

Nethereum

Pass the endpoint URL straight into new Web3(url) and every call routes over JSON-RPC to Ethereum. Each network method returns a TaskGetBalance.SendRequestAsync returns a BigInteger in wei, which Web3.Convert.FromWei turns into ETH. Always await these. Blocking on .Result or .Wait() inside an ASP.NET request can deadlock the synchronization context, so keep the call chain async all the way down.

using Nethereum.Web3;
using Nethereum.Web3.Accounts;
using Nethereum.Util;
using Nethereum.Hex.HexTypes;
public class EthereumService
{
private readonly Web3 _web3;
public EthereumService(string url)
{
_web3 = new Web3(url);
}
public async Task<decimal> GetBalanceAsync(string address)
{
var balance = await _web3.Eth.GetBalance.SendRequestAsync(address);
return Web3.Convert.FromWei(balance.Value);
}
public async Task<string> SendTransactionAsync(
string privateKey,
string toAddress,
decimal etherAmount)
{
var account = new Account(privateKey);
var web3 = new Web3(account, _web3.Client.Url);
var transaction = await web3.Eth.GetEtherTransferService()
.TransferEtherAsync(toAddress, etherAmount);
return transaction;
}
}
  • GitHub: https://github.com/Nethereum/Nethereum
  • Docs: https://docs.nethereum.com
  • Full Ethereum JSON-RPC coverage, including the EVM transaction and call APIs
  • Smart contract deployment and typed interaction from Solidity ABIs
  • HD wallet support (BIP-39/44) for key derivation and signing
  • Unity3D and Xamarin builds for games and mobile
  • IPC, RPC, and WebSocket transports — the last needed for eth_subscribe on wss://ethereum.therpc.io/YOUR_API_KEY

Smart Contract Integration

Hand the ABI string and a deployed address to _web3.Eth.GetContract(abi, contractAddress) and Nethereum gives you a Contract you can drive by function name. GetFunction("balanceOf").CallAsync<BigInteger>(...) runs an eth_call against the latest block — a read that costs no gas and returns immediately. State-changing calls go through SendTransactionAsync, which submits a signed transaction and hands back the hash you can track on etherscan.io. This is the pattern you use for an ERC-20 transfer or an Aave deposit alike.

public class SmartContractService
{
private readonly Web3 _web3;
private readonly Contract _contract;
public SmartContractService(string url, string contractAddress, string abi)
{
_web3 = new Web3(url);
_contract = _web3.Eth.GetContract(abi, contractAddress);
}
public async Task<T> CallFunctionAsync<T>(string functionName, params object[] parameters)
{
var function = _contract.GetFunction(functionName);
return await function.CallAsync<T>(parameters);
}
public async Task<string> ExecuteFunctionAsync(
string functionName,
string fromAddress,
params object[] parameters)
{
var function = _contract.GetFunction(functionName);
return await function.SendTransactionAsync(fromAddress, parameters);
}
}

ASP.NET Integration

Register EthereumService once in Program.cs (or Startup) — usually as a singleton, since the Web3 client is cheap to share and reuses its HTTP connection to the endpoint. Controllers then receive it through constructor injection, as the example below shows. Wrap each await in a try/catch: a malformed address or a transient RPC hiccup surfaces as an exception, and returning BadRequest(ex.Message) keeps a single bad request from bubbling up as a 500.

[ApiController]
[Route("api/[controller]")]
public class EthereumController : ControllerBase
{
private readonly EthereumService _ethereumService;
public EthereumController(EthereumService ethereumService)
{
_ethereumService = ethereumService;
}
[HttpGet("balance/{address}")]
public async Task<ActionResult<decimal>> GetBalance(string address)
{
try
{
var balance = await _ethereumService.GetBalanceAsync(address);
return Ok(balance);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
}

Event Handling

To watch a contract's logs, describe the event as a DTO and pass it to GetEvent<TEventDTO>(contractAddress). CreateFilterInput() builds the topic filter Ethereum expects, and polling GetFilterChanges returns decoded events — a Transfer from an ERC-20 token, for instance — as strongly typed objects rather than raw hex. For a live push instead of polling, run the same filter over the WebSocket endpoint and subscribe to logs.

public class EventMonitorService
{
private readonly Web3 _web3;
public async Task MonitorEventsAsync(string contractAddress, string eventName)
{
var filterAll = _web3.Eth.GetEvent<YourEventDTO>(contractAddress)
.CreateFilterInput();
var subscription = _web3.Eth.GetEvent<YourEventDTO>(contractAddress)
.GetFilterChanges(filterAll);
subscription.Subscribe(evt =>
{
Console.WriteLine($"New event: {evt.Event}");
});
}
}

Unity3D Integration

In a Unity game, build the Web3 instance once in Awake() or Start() pointing at the Ethereum endpoint, then keep it for the object's lifetime. The catch is MonoBehaviour: Unity only lets you mark Start() as async void, and async void swallows exceptions if you forget the try/catch. Keep the heavy lifting in async Task helpers and call them from Start() or a coroutine, so an unhandled RPC error logs through Debug.LogError instead of silently killing the frame.

public class EthereumUnityManager : MonoBehaviour
{
private Web3 _web3;
private async void Start()
{
_web3 = new Web3("https://ethereum.therpc.io/YOUR_API_KEY");
await InitializeWalletAsync();
}
private async Task InitializeWalletAsync()
{
try
{
var balance = await _web3.Eth.GetBalance.SendRequestAsync("YOUR_ADDRESS");
Debug.Log($"Wallet Balance: {Web3.Convert.FromWei(balance.Value)} ETH");
}
catch (Exception ex)
{
Debug.LogError($"Failed to initialize wallet: {ex.Message}");
}
}
}

Ready to call this in production?

Free tier covers personal projects. Pay-as-you-go scales without a card.