GoogleSheetsWrapper 1.0.38

There is a newer version of this package available.
See the version list below for details.
dotnet add package GoogleSheetsWrapper --version 1.0.38                
NuGet\Install-Package GoogleSheetsWrapper -Version 1.0.38                
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="GoogleSheetsWrapper" Version="1.0.38" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add GoogleSheetsWrapper --version 1.0.38                
#r "nuget: GoogleSheetsWrapper, 1.0.38"                
#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.
// Install GoogleSheetsWrapper as a Cake Addin
#addin nuget:?package=GoogleSheetsWrapper&version=1.0.38

// Install GoogleSheetsWrapper as a Cake Tool
#tool nuget:?package=GoogleSheetsWrapper&version=1.0.38                

GoogleSheetsWrapper

Nuget GitHub build status

Google Sheets API .NET Wrapper Library

This library allows you to use strongly typed objects against a Google Sheets spreadsheet without having to have knowledge on the Google Sheets API methods and protocols.

The following Google Sheets API operations are supported:

  • Reading all rows
  • Appending new rows
  • Deleting rows
  • Updating specific cells

All operations above are encapsulated in the SheetHelper class.

There are also base classes, BaseRecord and BaseRepository to simplify transforming raw Google Sheets rows into .NET objects.

A really simple console application using this library is included in this project below,

GoogleSheetsWrapper.SampleClient Project

To setup the sample application, you also need to configure User Secrets in Visual Studio to run it locally.

Extend BaseRecord and BaseRepository

Extending the BaseRecord class you can decorate properties with the SheetFieldAttribute to describe the column header name, the column index and the field type (ie string, DateTime, etc)

The column index is 1 based and not 0 based. The first column 'A' is equivalent to the column ID of 1.

public class TestRecord : BaseRecord
{
    [SheetField(
        DisplayName = "Name",
        ColumnID = 1,
        FieldType = SheetFieldType.String)]
    public string Name { get; set; }

    [SheetField(
        DisplayName = "Number",
        ColumnID = 2,
        FieldType = SheetFieldType.PhoneNumber)]
    public long? PhoneNumber { get; set; }

    [SheetField(
        DisplayName = "Price Amount",
        ColumnID = 3,
        FieldType = SheetFieldType.Currency)]
    public double? PriceAmount { get; set; }

    [SheetField(
        DisplayName = "Date",
        ColumnID = 4,
        FieldType = SheetFieldType.DateTime)]
    public DateTime? DateTime { get; set; }

    [SheetField(
        DisplayName = "Quantity",
        ColumnID = 5,
        FieldType = SheetFieldType.Number)]
    public double? Quantity { get; set; }

    public TestRecord() { }

    public TestRecord(IList<object> row, int rowId, int minColumnId = 1)
        : base(row, rowId, minColumnId)
    {
    }
}

Extending the BaseRepository allows you to define your own access layer to the Google Sheets tab you want to work with.

public class TestRepository : BaseRepository<TestRecord>
{
    public TestRepository() { }

    public TestRepository(SheetHelper<TestRecord> sheetsHelper)
        : base(sheetsHelper) { }
}

Core Operations (Strongly Typed)

Before you run the following code you will need to setup a Google Service Account and create a service account key. You also need to decide how to store your environment variables and secrets (ie the Google service account key)

More details can be found here

// You need to implement your own configuration management solution here!
var settings = AppSettings.FromEnvironment();

// Create a SheetHelper class for the specified Google Sheet and Tab name
var sheetHelper = new SheetHelper<TestRecord>(
    settings.GoogleSpreadsheetId,
    settings.GoogleServiceAccountName,
    settings.GoogleMainSheetName);

sheetHelper.Init(settings.JsonCredential);

// Get all rows from the sheet starting with the 1st row, between the 1st and 8th columns
// Leaving the last row blank tells Google Sheets to return all rows from the Sheet
var allRows = sheetHelper.GetRows("TabName", 1, 1, 8);

// Create a Repository for the TestRecord class
var repository = new TestRepository(sheetHelper);

// Validate that the header names match the expected format defined with the SheetFieldAttribute values
var result = repository.ValidateSchema();

if(!result.IsValid)
{
    throw new ArgumentException(result.ErrorMessage);
}

// Get all rows from the Google Sheet
var allRecords = repository.GetAllRecords();

// Get the first record
var firstRecord = allRecords.First();

// Update the PriceAmount field and save it back to Google Sheets
firstRecord.PriceAmount = 99.99;
repository.SaveField(firstRecord, (r) => r.PriceAmount);

// Delete the first record from Google Sheets
repository.DeleteRecord(firstRecord);

// Add a new record to the end of the Google Sheets tab
repository.AddRecord(new TestRecord()
{
    Name = "John",
    Number = 2021112222,
    PriceAmount = 250.50,
    Date = DateTime.Now(),
    Quantity = 123
});

Weakly Typed Operations

If you don't want to extend the BaseRecord class, you can use non typed operations with the SheetHelper class. Below is an example of that,

// Get the Google Spreadsheet Config Values
var serviceAccount = config["GOOGLE_SERVICE_ACCOUNT"];
var documentId = config["GOOGLE_SPREADSHEET_ID"];
var jsonCredsPath = config["GOOGLE_JSON_CREDS_PATH"];

// In this case the json creds file is stored locally, 
// but you can store this however you want to (Azure Key Vault, HSM, etc)
var jsonCredsContent = File.ReadAllText(jsonCredsPath);

// Create a new SheetHelper class
var sheetHelper = new SheetHelper(documentId, serviceAccount, "");
sheetHelper.Init(jsonCredsContent);

// Append new rows to the spreadsheet
var appender = new SheetAppender(sheetHelper);

// Appends weakly typed rows to the spreadsheeet
appender.AppendRows(new List<List<string>>()
{
    new List<string>(){"7/1/2022", "abc"},
    new List<string>(){"8/1/2022", "def"}
});

// Get all the rows for the first 2 columns in the spreadsheet
var rows = sheetHelper.GetRows(new SheetRange("", 1, 1, 2));

// Print out all the values from the result set
foreach (var row in rows)
{
    foreach (var col in row)
    {
        Console.Write($"{col}\t");
    }
    
    Console.Write("\n");
}

Append a CSV to Google Sheets

var appender = new SheetAppender(
    settings.GoogleSpreadsheetId, 
    settings.GoogleServiceAccountName, 
    settings.GoogleMainSheetName);

appender.Init(settings.JsonCredential);

var filepath = @"C:\Input\input.csv";

using (var stream = new FileStream(filepath, FileMode.Open))
{
    // Append the csv file to Google sheets, include the header row 
    // and wait 1000 milliseconds between batch updates 
    // Google Sheets API throttles requests per minute so you may need to play
    // with this setting. 
    appender.AppendCsv(
        stream, // The CSV FileStrem 
        true, // true indicating to include the header row
        1000); // 1000 milliseconds to wait every 100 rows that are batch sent to the Google Sheets API
}

Import a CSV to Google Sheets and Purge Existing Rows

If you wanted to delete the existing rows in your tab first, you can use SheetHelper methods to do that. Below is a sample of that,

// Create a SheetHelper class
var sheetHelper = new SheetHelper(
    settings.GoogleSpreadsheetId,
    settings.GoogleServiceAccountName,
    settings.GoogleMainSheetName);

sheetHelper.Init(settings.JsonCredential);

// Get the total row count for the existing sheet
var rows = sheetHelper.GetRows(new SheetRange("", 1, 1, 1));

// Delete all of the rows
sheetHelper.DeleteRows(1, rows.Count);

// Create the SheetAppender class
var appender = new SheetAppender(sheetHelper);

var filepath = @"C:\Input\input.csv";

using (var stream = new FileStream(filepath, FileMode.Open))
{
    // Append the csv file to Google sheets, include the header row 
    // and wait 1000 milliseconds between batch updates 
    // Google Sheets API throttles requests per minute so you may need to play
    // with this setting. 
    appender.AppendCsv(
        stream, // The CSV FileStrem 
        true, // true indicating to include the header row
        1000); // 1000 milliseconds to wait every 100 rows that are batch sent to the Google Sheets API
}

Export Google Sheet to CSV

var exporter = new SheetExporter(
    settings.GoogleSpreadsheetId, 
    settings.GoogleServiceAccountName, 
    settings.GoogleMainSheetName);

exporter.Init(settings.JsonCredential);

var filepath = @"C:\Output\output.csv";

using (var stream = new FileStream(filepath, FileMode.Create))
{
    // Query the range A1:G (ie 1st column, 1st row, 8th column and last row in the sheet)
    var range = new SheetRange("TAB_NAME", 1, 1, 8);
    exporter.ExportAsCsv(range, stream);
}

Export Google Sheet to Excel File

var exporter = new SheetExporter(
    settings.GoogleSpreadsheetId, 
    settings.GoogleServiceAccountName, 
    settings.GoogleMainSheetName);

exporter.Init(settings.JsonCredential);

var filepath = @"C:\Output\output.xlsx";

using (var stream = new FileStream(filepath, FileMode.Create))
{
    // Query the range A1:G (ie 1st column, 1st row, 8th column and last row in the sheet)
    var range = new SheetRange("TAB_NAME", 1, 1, 8);
    exporter.ExportAsExcel(range, stream);
}

Authentication

You need to setup a Google API Service Account before you can use this library.

  1. Create a service account. Steps to do that are documented below,

    https://cloud.google.com/docs/authentication/production#create_service_account

  2. After you download the JSON key, you need to decide how you want to store it and load it into the application.

  3. Use the service account identity that is created and add that email address to grant it permissions to the Google Sheets Spreadsheet you want to interact with.

  4. Configure your code with the following parameters to initialize a SheetHelper object

// You need to implement your own configuration management solution here!
var settings = AppSettings.FromEnvironment();

// Create a SheetHelper class for the specified Google Sheet and Tab name
var sheetHelper = new SheetHelper<TestRecord>(
    settings.GoogleSpreadsheetId,
    settings.GoogleServiceAccountName,
    settings.GoogleMainSheetName);

sheetHelper.Init(settings.JsonCredential);

Another good article on how to setup a Google Service Account can be found below on Robocorp's documentation site,

https://robocorp.com/docs/development-guide/google-sheets/interacting-with-google-sheets#create-a-google-service-account

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 was computed.  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. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen 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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.0.22 93 10/31/2024
2.0.21 72 10/31/2024
2.0.20 328 9/28/2024
2.0.19 79 9/28/2024
2.0.18 345 8/19/2024
2.0.17 21,881 7/20/2024
2.0.16 134 6/8/2024
2.0.15 139 6/3/2024
2.0.14 95 6/3/2024
2.0.13 108 5/29/2024
2.0.12 115 5/29/2024
2.0.11 396 1/20/2024
2.0.10 117 1/20/2024
2.0.9 2,397 1/8/2024
2.0.8 117 1/6/2024
2.0.7 122 1/6/2024
2.0.6 238 12/19/2023
2.0.5 269 11/28/2023
2.0.4 319 11/26/2023
2.0.3 122 11/25/2023
2.0.2 143 11/14/2023
2.0.1 110 11/14/2023
2.0.0 112 11/13/2023
1.0.58 23,180 11/13/2023
1.0.57 155 11/6/2023
1.0.56 124 11/6/2023
1.0.55 166 10/21/2023
1.0.54 1,559 5/9/2023
1.0.53 167 5/6/2023
1.0.52 48,056 2/7/2023
1.0.51 1,842 1/1/2023
1.0.50 289 12/29/2022
1.0.49 311 11/28/2022
1.0.48 304 11/28/2022
1.0.47 319 11/28/2022
1.0.46 306 11/28/2022
1.0.45 319 11/28/2022
1.0.44 326 11/22/2022
1.0.43 310 11/22/2022
1.0.42 316 11/22/2022
1.0.41 321 11/22/2022
1.0.40 334 11/22/2022
1.0.39 445 11/20/2022
1.0.38 315 11/19/2022
1.0.37 1,011 8/25/2022
1.0.36 405 8/18/2022
1.0.35 505 8/2/2022
1.0.34 414 6/18/2022
1.0.33 513 5/19/2022
1.0.32 397 5/17/2022
1.0.31 652 3/8/2022
1.0.30 438 3/8/2022
1.0.29 442 1/19/2022
1.0.28 297 12/20/2021
1.0.27 456 10/31/2021
1.0.26 309 10/28/2021
1.0.25 316 10/26/2021
1.0.24 342 10/17/2021
1.0.23 392 10/17/2021
1.0.22 348 10/16/2021
1.0.21 414 9/12/2021
1.0.20 412 8/26/2021
1.0.19 317 8/25/2021
1.0.18 308 8/25/2021
1.0.17 330 8/22/2021
1.0.16 326 8/22/2021
1.0.15 306 8/22/2021
1.0.14 331 8/21/2021
1.0.13 346 8/21/2021
1.0.12 337 8/21/2021
1.0.11 296 8/21/2021
1.0.10 306 8/21/2021
1.0.9 311 8/11/2021
1.0.8 308 8/9/2021
1.0.7 315 8/9/2021
1.0.6 338 8/8/2021
1.0.5 309 8/6/2021
1.0.4 343 8/5/2021
1.0.3 344 8/3/2021
1.0.2 335 8/3/2021
1.0.1 382 8/1/2021
1.0.0 304 8/1/2021