Interfacing .NET and Ethereum Blockchain Smart Contracts with Nethereum

.NET is the venerable framework that indie and enterprise developers alike have come to love. The ability to choose a variety of languages as well as deploy to a variety of platforms ranging from mobile to servers makes .NET a great choice for all kinds of applications. While .NET does a lot, it doesn’t do everything. For instance, one cannot write client side code to run in a browser in .NET (unless you use Silverlight…) nor is there currently a language supported by .NET that enables developers to write smart contracts.

The language of choice for smart contracts though is Solidity. Solidity is a purpose-built language that assumes many things about the environment it is running it, which pretty much marries it to blockchain technologies. It’s these baked in assumptions that conversely preclude other languages though.

Smart-contracts by themselves though are only half the story. For apps to be complete, smart contracts need something to call them by way of RPC’s. This is where Web3 clients come in. A Web3 client is simply the client side interface that enables client apps to interface with smart contracts running on Ethereum, so as long as one exists for a given language, then it can interface with Ethereum.

For .NET, really the only game in town for Ethereum is a project called Nethereum. (Nethereum is a portmanteau of .NET and Ethereum). This library attempts to replicate the same functionality provided by Web3.js available for JavaScript apps like those that run in a browser and with NodeJS

In this tutorial, we’ll deploy a smart contract to Ganache and then create a simple .NET app using .NET core to interface with the smart contract.

Create and Deploy a Smart Contract

  1. Download and install Ganache. Ganache is a personal blockchain useful for doing Ethereum development.
  2. In a terminal, command prompt, or Powershell session, install Truffle. Truffle is a framework and set of utilities that helps facilitate Solidity development of smart contracts. NPM is need to complete these commands.
     npm install -g truffle
    
  3. Create a folder and run truffle init in the folder.
     truffle init
    
  4. Truffle will create a few new folders: contract, test, and migration. In the contract folder, create a new file called Vote.sol in the contracts folder.
  5. Paste in the following code into the newly create Vote.sol and save the file. This contract simply tracks the vote count for 2 candidates. The contract uses the message sender (that is, an account address) as the voter. It only allows 1 vote per account.
     pragma solidity ^0.4.16;
    
     contract Vote {
    
         uint public candidate1;
         uint public candidate2;
         mapping (address => bool) public voted;
    
         function castVote(uint candidate) public  {
             require(!voted[msg.sender] && (candidate == 1 || candidate == 2));
             if(candidate == 1){
                 candidate1++;
             }else{
                 candidate2++;            
             }
             voted[msg.sender] = true;
         }
     }
    
  6. Create a new file in the migrations folder called 2_vote.js.
  7. Paste in the following code in the 2_vote.js file and save it.
     var vote = artifacts.require("Vote");
    
     module.exports = function(deployer) {
       // deployment steps
       deployer.deploy(vote);
     };
    
  8. Open truffle.js in the root of the folder you created and paste in the following code, then save the file. This configures Truffle to use Ganache.
     module.exports = {
       networks: {
         ganache: {
           host: "127.0.0.1",
           port: 7545,
           network_id: "*" // Match any network id
         }
       }
     };
    
  9. Start Ganache from the Start menu.
  10. Use Truffle to deploy the the smart contract. The ganache network is defined in the truffle.js file.
     truffle deploy --reset --network ganache
    
  11. Watch the output. You will see the output that looks something like the following. This is the address for the Vote contract. Copy and paste the hex string for later use.
     Vote: 0xe4e47451aad6c89a6d9e4ad104a7b77ffe1d3b36
    

Create a .NET app to use the Smart Contract

  1. In a new folder, use the dotnet command to create a new console app.
     dotnet create new console
    
  2. Install Nethereum packages.
     dotnet add package Nethereum.Web3
     dotnet add package Nethereum.Contracts
    
  3. Edit the Program.cs file. Paste over the default code with the following code. This will make the console prompt for an account address and for a users vote. Save the file.
     using System;
     using System.Numerics;
     using System.Threading.Tasks;
     using Nethereum.Contracts;
     using Nethereum.Hex.HexTypes;
     using Nethereum.Web3;
    
     namespace console
     {
         class Program
         {
             static void Main(string[] args)
             {
                 //The URL endpoint for the blockchain network.
                 string url = "HTTP://localhost:7545";
    
                 //The contract address.
                 string address = "0x345cA3e014Aaf5dcA488057592ee47305D9B3e10";
    
                 //The ABI for the contract.
                 string ABI = @"[{'constant':true,'inputs':[],'name':'candidate1','outputs':[{'name':'','type':'uint256'}],'payable':false,'stateMutability':'view','type':'function'},{'constant':false,'inputs':[{'name':'candidate','type':'uint256'}],'name':'castVote','outputs':[],'payable':false,'stateMutability':'nonpayable','type':'function'},{'constant':true,'inputs':[],'name':'candidate2','outputs':[{'name':'','type':'uint256'}],'payable':false,'stateMutability':'view','type':'function'},{'constant':true,'inputs':[{'name':'','type':'address'}],'name':'voted','outputs':[{'name':'','type':'bool'}],'payable':false,'stateMutability':'view','type':'function'}]";
    
                 //Creates the connecto to the network and gets an instance of the contract.
                 Web3 web3 = new Web3(url);
                 Contract voteContract = web3.Eth.GetContract(ABI, address);
    
                 //Reads the vote count for Candidate 1 and Candidate 2
                 Task<BigInteger> candidate1Function = voteContract.GetFunction("candidate1").CallAsync<BigInteger>();
                 candidate1Function.Wait();
                 int candidate1 = (int)candidate1Function.Result;
                 Task<BigInteger> candidate2Function = voteContract.GetFunction("candidate2").CallAsync<BigInteger>();
                 candidate2Function.Wait();
                 int candidate2 = (int)candidate2Function.Result;            
                 Console.WriteLine("Candidate 1 votes: {0}", candidate1);
                 Console.WriteLine("Candidate 2 votes: {0}", candidate2);
    
                 //Prompts for the account address.
                 Console.Write("Enter the address of your account: ");
                 string accountAddress = Console.ReadLine();
    
                 //Prompts for the users vote.
                 int vote = 0;
                 Console.Write("Press 1 to vote for candidate 1, Press 2 to vote for candidate 2: ");
                 Int32.TryParse(Convert.ToChar(Console.Read()).ToString(), out vote);
                 Console.WriteLine("You pressed {0}", vote);
    
                 //Executes the vote on the contract.
                 try{
                     HexBigInteger gas = new HexBigInteger(new BigInteger(400000));
                     HexBigInteger value = new HexBigInteger(new BigInteger(0));                 
                     Task<string> castVoteFunction = voteContract.GetFunction("castVote").SendTransactionAsync(accountAddress, gas, value, vote);
                     castVoteFunction.Wait();
                     Console.WriteLine("Vote Cast!");
                 }catch(Exception e){
                     Console.WriteLine("Error: {0}", e.Message);
                 }               
             }
         }
     }
    
  4. In Program.cs, paste over the value for address with the address for your deploy contact, then save the file.
     //The contract address.
     string address = "Your address goes here";
    
  5. Build the app.
     dotnet build
    
  6. Run the app.
     dotnet run
    
  7. You will see the app prompt you for input. Enter the address and vote. You can copy an account address from the Ganache GUI under the Accounts tab.
     Candidate 1 votes: 0
     Candidate 2 votes: 0
     Enter the address of your account: 0x627306090abaB3A6e1400e9345bC60c78a8BEf57
     Press 1 to vote for candidate 1, Press 2 to vote for candidate 2: 1
     You pressed 1
     Vote Cast!
    
  8. Run the app again and you will see the votes have been incremented.
     Candidate 1 votes: 1
     Candidate 2 votes: 0
     Enter the address of your account: 0xf17f52151EbEF6C7334FAD080c5704D77216b732
     Press 1 to vote for candidate 1, Press 2 to vote for candidate 2: 2
     You pressed 2
     Vote Cast!
    

With Nethereum, it’s easy to wire up a Smart Contract to any .NET app. Because Nethereum is .NET, it can be used in .NET Core apps, .NET Standard, Xamarin, and all sorts of Windows apps. With Nethereum, the power of Ethereum and .NET is now at your disposal!

 

Stay Informed

Sign up for the latest blogs, events, and insights.

We deliver solutions that accelerate the value of Azure.
Ready to experience the full power of Microsoft Azure?

Atmosera is thrilled to announce that we have been named GitHub AI Partner of the Year.

X