Trying to get Google spreadsheet table content by using C# client and Python.
C# client works fine while python returns error:
googleapiclient.errors.HttpError: <HttpError 404 when requesting https://sheets.googleapis.com/v4/spreadsheets/IAD2okAWZD7anbt5L4ybgD2dxHBGmsY6IkNIWHBQkBM/values/new%20first%20sheet%21A1?alt=json returned "Requested entity was not found.">
If I open link in error in browser I see error:
{
"error": {
"code": 403,
"message": "The request is missing a valid API key.",
"status": "PERMISSION_DENIED"
}
}
What might be wrong in Python client?
C# client:
private void button1_Click(object sender, EventArgs e)
{
string ApplicationName = "aaa";
UserCredential credential;
using (var stream =new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Google Sheets API service.
var service = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
String range = "new first sheet!A2:E";//mano
SpreadsheetsResource.ValuesResource.GetRequest request =service.Spreadsheets.Values.Get(spreadsheetId, range);
// https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
ValueRange response = request.Execute();
IList<IList<Object>> values = response.Values;
if (values != null && values.Count > 0)
{
Console.WriteLine("Name, Major");
foreach (var row in values)
{
// Print columns A and E, which correspond to indices 0 and 4.
if (row.Count==1 ) Console.WriteLine("{0}", row[0]);
else
Console.WriteLine("{0}, {1}", row[0], row[1]);
}
}
else
{
Console.WriteLine("No data found.");
}
Console.Read();
}
Python client:
class SS:
store = file.Storage('token.json')
try:
creds = store.get()
except Exception as e:
print(traceback.format_exc())
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
creds = tools.run_flow(flow, store)
service = build('sheets', 'v4', http=creds.authorize(Http()))
# Call the Sheets API
SPREADSHEET_ID = 'IAD2okAWZD7anbt5L4ybgD2dxHBGmsY6IkNIWHBQkBM' #my
RANGE_NAME = 'new first sheet!A1' #my
def __init__(self):
print("Constructing")
def get(self):
print("starting get")
result = self.service.spreadsheets().values().get( spreadsheetId=self.SPREADSHEET_ID, range=self.RANGE_NAME).execute()
values = result.get('values', [])
if not values:
print('No data found.')
else:
print('Name, Major:')
for row in values:
# Print columns A and E, which correspond to indices 0 and 4.
print('%s, %s' % (row[0], row[4]))
Related
From Cloud pub/sub push service i got a history id. Using that history id i am trying to read the recent mail's but It returns null.
I have configured cloud pub/sub push subscription and add a watch to "Unread" label.
Scenario 1:
I have received a push notification. From that push notification i have taken history id to get the recent messages. it's returning me null value.
Scenario 2:
I have logged into that configured mail id and then the message loaded in inbox. After that if i try to read i am getting the history list.
static string[] Scopes = { GmailService.Scope.MailGoogleCom };
static void Main(string[] args)
{
string UserId = "####.gmail.com";
UserCredential credential;
using (var stream =
new FileStream("client_secret_#####.json", FileMode.Open, FileAccess.Read))
{
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
UserId,
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
List<History> result = new List<History>();
UsersResource.HistoryResource.ListRequest request = service.Users.History.List(UserId);
//history id received from cloud pub/sub push subscription.
request.StartHistoryId = Convert.ToUInt64("269871");
do
{
try
{
ListHistoryResponse response = request.Execute();
if (response.History != null)
{
result.AddRange(response.History);
}
request.PageToken = response.NextPageToken;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
}
} while (!String.IsNullOrEmpty(request.PageToken));
foreach (var vHistory in result)
{
foreach (var vMsg in vHistory.Messages)
{
string date = string.Empty;
string from = string.Empty;
string subject = string.Empty;
string body = string.Empty;
var emailInfoRequest = service.Users.Messages.Get(UserId, vMsg.Id);
var emailInfoResponse = emailInfoRequest.Execute();
if(emailInfoResponse!= null)
{
foreach (var mParts in emailInfoResponse.Payload.Headers)
{
if (mParts.Name == "Date")
{
date = mParts.Value;
}
else if (mParts.Name == "From")
{
from = mParts.Value;
}
else if (mParts.Name == "Subject")
{
subject = mParts.Value;
}
if (date != "" && from != "")
{
if (emailInfoResponse.Payload.Parts != null)
{
foreach (MessagePart p in emailInfoResponse.Payload.Parts)
{
if (p.MimeType == "text/html")
{
byte[] data = FromBase64ForUrlString(p.Body.Data);
body = Encoding.UTF8.GetString(data);
}
else if(p.Filename!=null && p.Filename.Length>0)
{
string attId = p.Body.AttachmentId;
string outputDir = #"D:\#####\";
MessagePartBody attachPart = service.Users.Messages.Attachments.Get(UserId, vMsg.Id, attId).Execute();
String attachData = attachPart.Data.Replace('-', '+');
attachData = attachData.Replace('_', '/');
byte[] data = Convert.FromBase64String(attachData);
File.WriteAllBytes(Path.Combine(outputDir, p.Filename), data);
}
}
}
else
{
byte[] data = FromBase64ForUrlString(emailInfoResponse.Payload.Body.Data);
body = Encoding.UTF8.GetString(data);
}
}
}
}
}
}
public static byte[] FromBase64ForUrlString(string base64ForUrlInput)
{
int padChars = (base64ForUrlInput.Length % 4) == 0 ? 0 : (4 - (base64ForUrlInput.Length % 4));
StringBuilder result = new StringBuilder(base64ForUrlInput, base64ForUrlInput.Length + padChars);
result.Append(String.Empty.PadRight(padChars, '='));
result.Replace('-', '+');
result.Replace('_', '/');
return Convert.FromBase64String(result.ToString());
}
}
Please let me know how to read the full message using history id. when i receive push notification.
The Gmail Api documentation states that the Users.history:list method requires startHistoryId as a parameter to be executed, rather than giving you this parameter as a response. This is confusing, since it states as an optional parameter, but it is also specifies that it is required. The documentation also specifies:
The supplied startHistoryId should be obtained from the historyId of a
message, thread, or previous list response.
I suggest you to test the methods you use first with "Try this API" and OAuth 2.0 Playground. This makes it easier to understand which parameters you need to supply and which responses you can obtain from each method.
I have dealt with this. The point is that the history_id you are receiving is to be interpreted like the "latest moment when something happened". So, in order to make this work, you MUST use a history_id coming from a previous execution (that, don't forget, in GMail Push API means that you have to implement the initial full sync, or at the very least you should be executing a second run of your partial sync), which will return the events that span from the previous history_id to the one you just received.
I have just published an article on medium, since the detail of the history_id, in my opinion, can be a little sneaky. Article is here.
I have created an ASP.Net Core MVC project and integrated the Google Calendar API:
Google.Apis.Calendar.v3 with a NuGet package
I followed this guide.
it seems to work since i see some records from my calendar in the output window of my visual studio
but the page themself never stops loading?
i removed the default pages and events in the HomeController only Index is left
and replaced the code from the program.cs with the code from google.
namespace CalendarQuickstart
{
class Program
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/calendar-dotnet-quickstart.json
static string[] Scopes = { CalendarService.Scope.CalendarReadonly };
static string ApplicationName = "Google Calendar API .NET Quickstart";`
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Google Calendar API service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Define parameters of request.
EventsResource.ListRequest request = service.Events.List("primary");
request.TimeMin = DateTime.Now;
request.ShowDeleted = false;
request.SingleEvents = true;
request.MaxResults = 10;
request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime;
// List events.
Events events = request.Execute();
Console.WriteLine("Upcoming events:");
if (events.Items != null && events.Items.Count > 0)
{
foreach (var eventItem in events.Items)
{
string when = eventItem.Start.DateTime.ToString();
if (String.IsNullOrEmpty(when))
{
when = eventItem.Start.Date;
}
Console.WriteLine("{0} ({1})", eventItem.Summary, when);
}
}
else
{
Console.WriteLine("No upcoming events found.");
}
Console.Read();
}
}
}
so I can't see my index view.
replacing the List Events with :
CreateWebHostBuilder(args).Build().Run();
and adding :
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
i am able to see the Index Page/View again
I started with the basics and learned how to insert a fixed bit of rows to a Google Sheet from my program now I've been trying to figure out how to append output from a SQL. I have a C# program that calls a stored procedure or it can do a select * from table. Simply trying to insert the results/output of that select into a Google Sheet. Every example I find is dealing with hard coded fixed rows and columns. My select produces less than 2000 lines of output. Appreciate the help!
namespace CS_Gsheet1
{
class Program
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/sheets.googleapis.com-dotnet-quickstart.json
//static string[] Scopes = { SheetsService.Scope.SpreadsheetsReadonly };
//static string ApplicationName = "Google Sheets API .NET Quickstart";
static string[] Scopes = { SheetsService.Scope.Spreadsheets };
static string ApplicationName = "Test3";
static void Main(string[] args)
{
var service = AuthorizeGoogleApp();
String spreadsheetId = "sheetIDstring";
// Write to specified sheet
String writeRange = "Sheet1!A1:K";
ValueRange valueRange = new ValueRange { MajorDimension = "ROWS" };
IList<object> dataList = new List<object>();
using(SqlConnection myConnection = new SqlConnection("connectionstring"))
{
myConnection.Open();
using(SqlCommand cmd = new SqlCommand("storedproc-selectsmultiplecolumnsandrows", myConnection))
{
cmd.CommandType = CommandType.StoredProcedure;
using(SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// dataList.Add(reader.GetString(0));
// dataList.Add(reader.GetValue(0));
IList<IList<Object>> values = new List<IList<Object>>();
values.Add(dataList);
}
}
}
}
// Data is accessible through the DataReader object here.
ValueRange valueDataRange = new ValueRange() { MajorDimension = "ROWS" };
valueDataRange.Values = new List<IList<object>> { dataList };
int c = dataList.Count;
Console.WriteLine("dataList Count {0}", c);
for (int i = 0; i < c; i++)
{
// API to append data to sheet
SpreadsheetsResource.ValuesResource.AppendRequest appendRequest = service.Spreadsheets.Values.Append(valueDataRange, spreadsheetId, writeRange);
appendRequest.ValueInputOption = SpreadsheetsResource.ValuesResource.AppendRequest.ValueInputOptionEnum.RAW;
appendRequest.InsertDataOption = SpreadsheetsResource.ValuesResource.AppendRequest.InsertDataOptionEnum.INSERTROWS;
AppendValuesResponse appendValueResponse = appendRequest.Execute();
}
}
private static SheetsService AuthorizeGoogleApp()
{
UserCredential credential;
using (var stream = new FileStream("client_secret.json", FileMode.Open, FileAccess.ReadWrite))
{
string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/sheets.googleapis.com-dotnet-quickstart.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
// Create Google Sheets API service.
var service = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
return service;
}
}
}
}
I was able to tweak this solution to get the process to work without requesting a quota increase from Google. It does not run very fast, but ok for ~1000 records.
https://github.com/jeffcrowder/GoogleSheetsAPIExample/blob/master/GoogleSheetsAPIExample/Program.cs
I am working with the GData api to import products to my merchant feed. The code is as follows:
List<ProductEntry> newEntries = new List<ProductEntry>();
foreach (Product prod in ent.Products.Where(i => !i.IsDeleted && i.IsDisplayed && i.Price > 0))
{
newEntries.Add(prod.GetNewEntry());
}
string GoogleUsername = "nope#gmail.com";
string GooglePassword = "*****";
ContentForShoppingService service = new ContentForShoppingService("MY STORE");
service.setUserCredentials(GoogleUsername, GooglePassword);
service.AccountId = "*******";
service.ShowWarnings = true;
ProductFeed pf = service.InsertProducts(newEntries);
r.Write(pf.Entries.Count.ToString());
This code is returning to me 1 entry, rather than the 400+ it should, and that 1 entry is empty with no error or warning info. Nothing shows on my merchant center dash. Any ideas on what might be occurring here?
OR - how can I get more details on what is going on?
First of all create a service account on Google Developers
Console if you don't have one already.
NuGet package Google.Apis.ShoppingContent.v2
after you do whats mentioned on the link you'll get
a ClientId
a ClientSecret
those we will be using to authenticate.
var credentials = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets() {
ClientId = "yourclientid",
ClientSecret = "yourclientsecret" },
new string[] { ShoppingContentService.Scope.Content },
"user",
CancellationToken.None).Result;
//make this a global variable or just make sure you pass it to InsertProductBatch or any function that needs to use it
service = new ShoppingContentService(new BaseClientService.Initializer()
{
HttpClientInitializer = credentials,
ApplicationName = "Your-app-name"
});
Now for the insert part:
private async Task<List<Product>> InsertProductBatch(IEnumerable<Product> products, ulong merchantaccountid)
{
// Create a batch request.
BatchRequest request = new BatchRequest(service);
List<Product> responseproducts = new List<Product>();
foreach (var p in products)
{
ProductsResource.InsertRequest insertRequest =
service.Products.Insert(p, merchantaccountid);
request.Queue<Product>(
insertRequest,
(content, error, index, message) =>
{
responseproducts.Add(content);
//ResponseProducts.Add(content);
if (content != null)
{
//product inserted successfully
}
AppendLine(String.Format("Product inserted with id {0}", ((Product)content).Id));
if (error != null)
{
//there is an error you can access the error message though error.Message
}
});
}
await request.ExecuteAsync(CancellationToken.None);
return responseproducts;
}
And thats all to it.
After many trials and errors I managed to compile a piece of code which should return Entities' values from Google Datastore (it's SQL-like db). Code I used:
static async void Run()
{
UserCredential credential;
using (var stream = new FileStream(#"c:/fakepath/client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { DatastoreService.Scope.Datastore }, "user", CancellationToken.None);
}
// Create the service.
var service = new DatastoreService(new BaseClientService.Initializer
{
ApplicationName = "My Project",
HttpClientInitializer = credential
});
// Run the request.
Console.WriteLine("Executing a list request...");
var request = new LookupRequest();
var key = new Google.Apis.Datastore.v1beta2.Data.Key();
key.Path = new List<KeyPathElement> { new KeyPathElement() { Kind = "book", Name = "title42" } };
request.Keys = new List<Key>() { key };
var lookup = service.Datasets.Lookup(request, "project-name-192"); //yea
var response = lookup.Execute();
// Display the results.
if (response.Found != null)
{
foreach (var x in response.Found)
{
foreach (var y in x.Entity.Properties)
{
Console.WriteLine(y.Key.FirstOrDefault() + " " + y.Value);
}
}
}
}
Error I get:
So, what am I missing? I did just like in example on docs.
You need to go to:
https://console.developers.google.com/project/apps~{your-app-name}/apiui/credential
and use http://localhost:63324/authorize/ as the redirect url.
Remember to change it to your production url when you deploy