C# using Google Classroom API Read List of Students - c#

I am trying to write a console app for our elementary school which will read courses, students, coursework (etc) from Google Classrooms and write it to our SQL Server database. This is the first time I have ever used an API and I have very little experience with C# - but school starts in two days, so I'm using Google searches to figure out how to do it.
I pasted my code below that successfully reads the courses from Google Classroom and writes them to our SQL Server. I thought I could use the same logic for the rest of the tables (students, Coursework, etc). However, when I tried to add students, there is a problem with this line (list is underlined in red):
CoursesResource.ListRequest RequestStudents = service.Courses.Students.List();
I can't figure out what is wrong and can't seem to find an example online.
Any help would be very appreciated.
Thanks,
JMC
namespace ClassroomQuickstart
{
class Program
{
static string ApplicationName = "Google Classroom ETL Process";
static string[] Scopes =
{
ClassroomService.Scope.ClassroomAnnouncementsReadonly,
ClassroomService.Scope.ClassroomCoursesReadonly,
ClassroomService.Scope.ClassroomCourseworkStudentsReadonly,
ClassroomService.Scope.ClassroomGuardianlinksStudentsReadonly,
ClassroomService.Scope.ClassroomRostersReadonly,
ClassroomService.Scope.ClassroomStudentSubmissionsStudentsReadonly,
ClassroomService.Scope.ClassroomTopicsReadonly
};
static void Main(string[] args)
{
UserCredential credential;
using (var stream = new FileStream("MyCredentials.json", FileMode.Open, FileAccess.Read))
{
string credPath = "TokenGoogleClassroomETLClient";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create the service.
var service = new ClassroomService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
//==============================================================================================
// Transfer courses
// Define request parameters
CoursesResource.ListRequest RequestCourses = service.Courses.List();
RequestCourses.PageSize = 1000;
ListCoursesResponse ResponseCourses = RequestCourses.Execute();
if (ResponseCourses.Courses != null && ResponseCourses.Courses.Count > 0)
{
Console.WriteLine("\n=========================================");
Console.WriteLine("\nTransferring Google Classrooms Courses:");
// prepare the parameterized SQL statement
StringBuilder sb = new StringBuilder();
sb.Append("INSERT INTO GoogleClassroomsCourse ");
sb.Append("(CourseID, CourseName, CourseSection, DescriptionHeading, Description, Room, OwnerID, CreationTime, UpdateTime, EnrollmentCode, CourseState, AlternateLink, TeacherGroupEmail, CourseGroupEmail, GuardianEnabled, CalendarID) ");
sb.Append("VALUES (#Id , #Name, #Section, #DescriptionHeading, #Description, #Room, #OwnerId, #CreationTime, #UpdateTime, #EnrollmentCode, #CourseState, #AlternateLink, #TeacherGroupEmail, #CourseGroupEmail, #GuardiansEnabled, #CalendarId)");
String sql = sb.ToString();
// establish connecion to the SQL Server
using (SqlConnection connection = new SqlConnection("MyConnectionString"))
{
connection.Open();
// process each course record in Google Classrom
foreach (var course in ResponseCourses.Courses)
{
// ouput the course name and id to the console
Console.WriteLine("{0} ({1})", course.Name, course.Id);
// populate the variables from the current course record
string Id = course.Id ?? "";
string Name = course.Name ?? "";
string Section = course.Section ?? "";
string DescriptionHeading = course.DescriptionHeading ?? "";
string Description = course.Description ?? "";
string Room = course.Room ?? "";
string OwnerId = course.OwnerId ?? "";
string CreationTime = course.CreationTime.ToString() ?? "";
string UpdateTime = course.UpdateTime.ToString() ?? "";
string EnrollmentCode = course.EnrollmentCode ?? "";
string CourseState = course.CourseState ?? "";
string AlternateLink = course.AlternateLink ?? "";
string TeacherGroupEmail = course.TeacherGroupEmail ?? "";
string CourseGroupEmail = course.CourseGroupEmail ?? "";
string GuardiansEnabled = course.GuardiansEnabled.ToString() ?? "";
string CalendarId = course.CalendarId ?? "";
// write the record to sql database
try
{
using (SqlCommand command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("#Id", Id);
command.Parameters.AddWithValue("#Name", Name);
command.Parameters.AddWithValue("#Section", Section);
command.Parameters.AddWithValue("#DescriptionHeading", DescriptionHeading);
command.Parameters.AddWithValue("#Description", Description);
command.Parameters.AddWithValue("#Room", Room);
command.Parameters.AddWithValue("#OwnerId", OwnerId);
command.Parameters.AddWithValue("#CreationTime", CreationTime);
command.Parameters.AddWithValue("#UpdateTime", UpdateTime);
command.Parameters.AddWithValue("#EnrollmentCode", EnrollmentCode);
command.Parameters.AddWithValue("#CourseState", CourseState);
command.Parameters.AddWithValue("#AlternateLink", AlternateLink);
command.Parameters.AddWithValue("#TeacherGroupEmail", TeacherGroupEmail);
command.Parameters.AddWithValue("#CourseGroupEmail", CourseGroupEmail);
command.Parameters.AddWithValue("#GuardiansEnabled", GuardiansEnabled);
command.Parameters.AddWithValue("#CalendarId", CalendarId);
int rowsAffected = command.ExecuteNonQuery();
}
}
catch (SqlException e)
{
Console.WriteLine(e.ToString());
}
//==============================================================================================
// Transfer students in the current course
// Define request parameters.
CoursesResource.ListRequest RequestStudents = service.Courses.Students.List();
RequestStudents.PageSize = 1000;
ListStudentsResponse ResponseStudents = RequestStudents.Execute();
if (ResponseStudents.Students != null && ResponseStudents.Students.Count > 0)
{
Console.WriteLine("\n=========================================");
Console.WriteLine("\nTransferring Google Classrooms Students:");
Console.WriteLine(ResponseStudents.Students.Count.ToString());
}
}
connection.Close();
}
}
else
{
Console.WriteLine("No courses found.");
}
Console.Read();
}
}
}

Looking further at the signature, Students.List requires a course ID as a parameter, which is currently not provided. On top of this, the return type for Students.List is CoursesResource.StudentsResource.ListRequest. To fix, replace the line with:
CoursesResource.StudentsResource.ListRequest RequestStudents = service.Courses.Students.List(course.Id);

Related

gmail api returning null for a specific history id. History id received from Cloud Pub/Sub push subscription

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.

Appending data to a Google Sheet from C# called SqlCommand

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

How to retrieve my Gmail messages using Gmail API?

What I want to achieve:
I'm using the Gmail API and basically I would like to connect to my GMail account to read my emails, of INBOX category, and get basic info for each message (title/subject, from, to, date, and the sender).
Problems:
I'm trying to adapt this Google sample, written in C#, to my own needs, I'm searching for a solution in C# or Vb.Net, no matter.
(Be aware that Google shows different code examples for different user-countries, so the code of that webpage maybe will not be the same for every one, that Google's logic really sucks.)
The problems I have with the code below, are these:
I'm getting an empty value in lblInbox.MessagesTotal property.
msgItem.Raw property is always empty too.
I haven't yet discovered how to parse only the messages that are inside the INBOX category.
I haven't yet discovered how to determine if a message is read or unread.
I haven't yet discovered how to determine the basic info of a message (subject, from, to, date, sender).
This is what I've tried, note that when adapting the Google's sample, I assumed that "user" argument should be the Gmail user account name ("MyEmail#GMail.com"), but I'm not sure it should be that.
Imports System.Collections.Generic
Imports System.IO
Imports System.Linq
Imports System.Text
Imports System.Threading
Imports System.Threading.Tasks
Imports Google.Apis.Auth.OAuth2
Imports Google.Apis.Services
Imports Google.Apis.Util.Store
Imports Google.Apis.Gmail
Imports Google.Apis.Gmail.v1
Imports Google.Apis.Gmail.v1.Data
Imports Google.Apis.Gmail.v1.UsersResource
Public Class Form1 : Inherits Form
Private Async Sub Test() Handles MyBase.Shown
Await GmailTest()
End Sub
Public Async Function GmailTest() As Task
Dim credential As UserCredential
Using stream As New FileStream("C:\GoogleAPIKey.json", FileMode.Open, FileAccess.Read)
credential = Await GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,
{GmailService.Scope.MailGoogleCom},
"MyEmail#GMail.com",
CancellationToken.None)
End Using
' Create the service.
Dim service As New GmailService(New BaseClientService.Initializer() With {
.HttpClientInitializer = credential,
.ApplicationName = "What I need to put here?"
})
' Get the "INBOX" label/category.
Dim lblReq As UsersResource.LabelsResource.ListRequest = service.Users.Labels.List("me")
Dim lblInbox As Data.Label = lblReq.Execute().Labels.Where(Function(lbl) lbl.Name = "INBOX").Single
Dim msgCount As Integer? = lblInbox.MessagesTotal
MsgBox("Messages Count: " & msgCount)
If (msgCount <> 0) Then
' Define message parameters of request.
Dim msgReq As UsersResource.MessagesResource.ListRequest = service.Users.Messages.List("me")
' List messages of INBOX category.
Dim messages As IList(Of Data.Message) = msgReq.Execute().Messages
Console.WriteLine("Messages:")
If (messages IsNot Nothing) AndAlso (messages.Count > 0) Then
For Each msgItem As Data.Message In messages
MsgBox(msgItem.Raw)
Next
End If
End If
End Function
End Class
Question:
I will ask for the most important need (however, any help to solve the other mentioned problems are very welcome):
In C# or VB.Net, how can I obtain a collection to iterate all the emails that are in the INBOX group?.
Update:
This is the code that I'm using right now, the intention is to retrieve a collection of all Messages of the specified mailbox label, the problem is that the Payload and Body member of newMsg object is null, so I can't read the email.
What I'm doing wrong?.
Public Async Function GetMessages(ByVal folder As Global.Google.Apis.Gmail.v1.Data.Label) As Task(Of List(Of Global.Google.Apis.Gmail.v1.Data.Message))
If Not (Me.isAuthorizedB) Then
Throw New InvalidOperationException(Me.authExceptionMessage)
Else
Dim msgsRequest As UsersResource.MessagesResource.ListRequest = Me.client.Users.Messages.List("me")
With msgsRequest
.LabelIds = New Repeatable(Of String)({folder.Id})
.MaxResults = 50
'.Key = "YOUR API KEY"
End With
Dim msgsResponse As ListMessagesResponse = Await msgsRequest.ExecuteAsync()
Dim messages As New List(Of Global.Google.Apis.Gmail.v1.Data.Message)
Do While True
For Each msg As Global.Google.Apis.Gmail.v1.Data.Message In msgsResponse.Messages
Dim msgRequest As UsersResource.MessagesResource.GetRequest = Me.client.Users.Messages.Get("me", msg.Id)
msgRequest.Format = MessagesResource.GetRequest.FormatEnum.Full
Dim newMsg As Message = Await msgRequest.ExecuteAsync()
messages.Add(newMsg)
Next msg
If Not String.IsNullOrEmpty(msgsResponse.NextPageToken) Then
msgsRequest.PageToken = msgsResponse.NextPageToken
msgsResponse = Await msgsRequest.ExecuteAsync()
Else
Exit Do
End If
Loop
Return messages
End If
End Function
Currently for some reason or another many of the properties are coming back null from any of the requests. We can still get around that if we have a list of the email ids. We then can use these email ids to send out another request to retrieve further details: from, date, subject, and body. #DalmTo was on the right track as well, but not close enough about the headers as it has changed recently which will require a few more requests.
private async Task getEmails()
{
try
{
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
// This OAuth 2.0 access scope allows for read-only access to the authenticated
// user's account, but not other types of account access.
new[] { GmailService.Scope.GmailReadonly, GmailService.Scope.MailGoogleCom, GmailService.Scope.GmailModify },
"NAME OF ACCOUNT NOT EMAIL ADDRESS",
CancellationToken.None,
new FileDataStore(this.GetType().ToString())
);
}
var gmailService = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = this.GetType().ToString()
});
var emailListRequest = gmailService.Users.Messages.List("EMAILADDRESSHERE");
emailListRequest.LabelIds = "INBOX";
emailListRequest.IncludeSpamTrash = false;
//emailListRequest.Q = "is:unread"; // This was added because I only wanted unread emails...
// Get our emails
var emailListResponse = await emailListRequest.ExecuteAsync();
if (emailListResponse != null && emailListResponse.Messages != null)
{
// Loop through each email and get what fields you want...
foreach (var email in emailListResponse.Messages)
{
var emailInfoRequest = gmailService.Users.Messages.Get("EMAIL ADDRESS HERE", email.Id);
// Make another request for that email id...
var emailInfoResponse = await emailInfoRequest.ExecuteAsync();
if (emailInfoResponse != null)
{
String from = "";
String date = "";
String subject = "";
String body = "";
// Loop through the headers and get the fields we need...
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 && emailInfoResponse.Payload.Body != null)
{
body = emailInfoResponse.Payload.Body.Data;
}
else
{
body = getNestedParts(emailInfoResponse.Payload.Parts, "");
}
// Need to replace some characters as the data for the email's body is base64
String codedBody = body.Replace("-", "+");
codedBody = codedBody.Replace("_", "/");
byte[] data = Convert.FromBase64String(codedBody);
body = Encoding.UTF8.GetString(data);
// Now you have the data you want...
}
}
}
}
}
}
catch (Exception)
{
MessageBox.Show("Failed to get messages!", "Failed Messages!", MessageBoxButtons.OK);
}
}
static String getNestedParts(IList<MessagePart> part, string curr)
{
string str = curr;
if (part == null)
{
return str;
}
else
{
foreach (var parts in part)
{
if (parts.Parts == null)
{
if (parts.Body != null && parts.Body.Data != null)
{
str += parts.Body.Data;
}
}
else
{
return getNestedParts(parts.Parts, str);
}
}
return str;
}
}
Currently, this method will retrieve all email ids and for each email id get the subject,from, date and body of each email. There are comments throughout the method. If there is something you do not understand, please let me know. On another note: this was tested again before posting this as an answer.
sorry this is not an answer, i can't add a comment to Zaggler's answer(just joined), so just post as a new answer, Zaggler's answer is very good, but there is a small problem. when the email body has more then one part. the Convert.FromBase64..... doesn't work on two joined base64 strings. so an exception will be occure. better convert then joined the body parts.
some one ask for the code, and here is the completed tested code. most of them are copied from Zaggler, but i end up with some exceptions. so i traced down to the problem described above.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Gmail.v1;
using Google.Apis.Gmail.v1.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
namespace GmailTests
{
class Program
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/gmail-dotnet-quickstart.json
static string[] Scopes = { GmailService.Scope.GmailModify };
static string ApplicationName = "Gmail API .NET Quickstart";
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/gmail-dotnet-quickstart2.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 Gmail API service.
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
var re = service.Users.Messages.List("me");
re.LabelIds = "INBOX";
re.Q = "is:unread"; //only get unread;
var res = re.Execute();
if (res != null && res.Messages != null)
{
Console.WriteLine("there are {0} emails. press any key to continue!", res.Messages.Count);
Console.ReadKey();
foreach (var email in res.Messages)
{
var emailInfoReq = service.Users.Messages.Get("me", email.Id);
var emailInfoResponse = emailInfoReq.Execute();
if (emailInfoResponse != null)
{
String from = "";
String date = "";
String subject = "";
String body = "";
//loop through the headers and get the fields we need...
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 && emailInfoResponse.Payload.Body != null)
body = DecodeBase64String(emailInfoResponse.Payload.Body.Data);
else
body = GetNestedBodyParts(emailInfoResponse.Payload.Parts, "");
//now you have the data you want....
}
}
//Console.Write(body);
Console.WriteLine("{0} -- {1} -- {2}", subject, date, email.Id);
Console.ReadKey();
}
}
}
}
static String DecodeBase64String(string s)
{
var ts = s.Replace("-", "+");
ts = ts.Replace("_", "/");
var bc = Convert.FromBase64String(ts);
var tts = Encoding.UTF8.GetString(bc);
return tts;
}
static String GetNestedBodyParts(IList<MessagePart> part, string curr)
{
string str = curr;
if (part == null)
{
return str;
}
else
{
foreach (var parts in part)
{
if (parts.Parts == null)
{
if (parts.Body != null && parts.Body.Data != null)
{
var ts = DecodeBase64String(parts.Body.Data);
str += ts;
}
}
else
{
return GetNestedBodyParts(parts.Parts, str);
}
}
return str;
}
}
}
}
First: up-vote #codexer 's answer.
Second, use the following function in his code to decode the base64URL encoded body. Google not only base64 encoded the body, it is also URL encoded :-/
/// <summary>
/// Turn a URL encoded base64 encoded string into readable UTF-8 string.
/// </summary>
/// <param name="sInput">base64 URL ENCODED string.</param>
/// <returns>UTF-8 formatted string</returns>
private string DecodeURLEncodedBase64EncodedString(string sInput)
{
string sBase46codedBody = sInput.Replace("-", "+").Replace("_", "/").Replace("=", String.Empty); //get rid of URL encoding, and pull any current padding off.
string sPaddedBase46codedBody = sBase46codedBody.PadRight(sBase46codedBody.Length + (4 - sBase46codedBody.Length % 4) % 4, '='); //re-pad the string so it is correct length.
byte[] data = Convert.FromBase64String(sPaddedBase46codedBody);
return Encoding.UTF8.GetString(data);
}
The user parameter in GoogleWebAuthorizationBroker.AuthorizeAsync is just used by FileDatastore to store your credentials check my tutorial Google .net – FileDatastore demystified for more information.
My VB.net is very rusty like 6 years rusty but in C# you could do something like this
UsersResource.MessagesResource.ListRequest request = service.Users.Messages.List("Users email address");
var response = request.Execute();
foreach (var item in response.Messages) {
Console.WriteLine(item.Payload.Headers);
}
MessageResource.ListRequest returns a list of message objects you can loop though them.
Users.Messages contains header which should have the subject and the to and from.
I also have a really old C# tutorial on gmail that might help.
Update to answer your update:
What happens when you remove:
.LabelIds = New Repeatable(Of String)({folder.Id})
labelIds string Only return messages with labels that match all of the specified label IDs.
It appears you are sending a folder id. try using user.lables.list which returns Lists all labels in the user's mailbox
UsersResource.MessagesResource.GetRequest getReq = null;
Google.Apis.Gmail.v1.Data.Message msg = null;
getReq = gmailServiceObj.Users.Messages.Get(userEmail, MessageID);
getReq.Format = UsersResource.MessagesResource.GetRequest.FormatEnum.Raw;
msg = getReq.Execute();
string converted = msg.Raw.Replace('-', '+');
converted = converted.Replace('_', '/');
byte[] decodedByte = Convert.FromBase64String(converted);
converted = null;
f_Path = Path.Combine(m_CloudParmsObj.m_strDestinationPath,MessageID + ".eml");
if (!Directory.Exists(m_CloudParmsObj.m_strDestinationPath))
Directory.CreateDirectory(m_CloudParmsObj.m_strDestinationPath);
// Create eml file
File.WriteAllBytes(f_Path, decodedByte);
We can get the .eml file with all message properties like this.
codedBody = codedBody.Replace(" ", "+");
codedBody = codedBody.Replace("=", "+");
to parse the body part I recommend adding these lines of code as well

C# Webservice stucks. Need to override published file to restart

Please help me, I'm facing a fatal problem here. If someone could fix this, I swear I will treat u to a huge drink whenever u step into my country (Vietnam). Ok here's the problem: I'm coding a webservice for multi connection simultaneously from tablet (around 100 clients). It ran well but recently whenever high traffic occurs, my webservice seems to stuck somehow and I need to copy - override the published file of webservice in order for it to run again (restart website in IIS is no use) ...
This is my w/s code for handling the data:
public string Info_Handling(string id, string name, string strDetails)
{
string checkExist = "";
string str = "";
string str2 = "";
MLL_Customer _customerClient = new MLL_Customer();
MLL_CustomerCategory _categoryClient = new MLL_CustomerCategory();
MLL_Product _productClient = new MLL_Product();
MLL_SampleProduct _sampleClient = new MLL_SampleProduct();
if (_customerClient.CheckExistCustomer(id, name.ToUpper(), 2) == 1) // SID & NAME
{
checkExist = "EXIST";
}
using (SqlConnection connection = new SqlConnection(ConfigurationSettings.AppSettings["Main.ConnectionString"]))
{
connection.Open();
SqlTransaction trans = connection.BeginTransaction("XXX");
try
{
// ID Example: 11 means VIP - 12 means Normal - 13 means ples... jkg
// First - Insert Customer
string strCustomerCategory = _categoryClient.SelectCategoryByID(id).ToString();
if (!checkExist.Equals("EXIST"))
{
Customer businessObject = new Customer();
businessObject.ID = sid;
businessObject.Name = name.ToUpper();
businessObject.CategoryID = strCustomerCategory;
str = "" + _customerClient.Insert(businessObject, connection, trans);
}
// Second Insert Product spliting from a string Ex: "TV&Laptop&CD"
string[] productDetails = strDetails.Split(new char[] { '&' });
object obj3;
SampleProduct objSample;
Product objProduct;
for (int j = 0; j < productDetails.Length; j++)
{
if (_productClient.CheckExist(id, productDetails[j])) == null) // Check if customer already owns this product
{
// Get the properties of sample product.
objSample = _sampleClient.SelectSampleProduct(productDetails[j]);
objProduct = new Product();
objProduct.SID = sid;
objProduct.Testcode = objSample.TestCode;
objProduct.Category = objSample.Category;
objProduct.Unit = objSample.Unit;
objProduct.Price = objSample.Price;
if (_productClient.Insert(objProduct, connection, trans) != 0)
{
str2 = str2 + "&" + objProduct.Testcode;
// return the code of product in order to see which product has been inserted successfully
}
}
}
trans.Commit();
SqlConnection.ClearAllPools();
}
catch (Exception exception)
{
str = "0";
str2 = exception.Message + exception.Source;
try
{
trans.Rollback();
}
catch (Exception)
{
}
}
}
if (!str2.Equals(""))
{
return (str + "&" + id + str2);
}
return ("0&" + sid + str);
}
I modified the code but this is basically how i roll. Could anyone plz tell me some solution. Deeply thank u.
1 more thing about ClearAllPools() method: I know how it works but I dont even know why I need it. Without this, my data will be messed up terrible. CategoryID of one customer will be assigned for another customer sometimes. ???? How could it happened ?? HELP

IsPostBack Issue

I am trying to do a 3 tier volunteers sign up for packaging session system. First, on the page load, I get the details of certain packaging session:
if (!IsPostBack)
{
string packingID = Request.QueryString["id"];
packingIndv = packing.getPacking(packingID);
if (packingIndv == null)
{
lbl_msg.Text = "Error in getting packing session details!";
}
else
{
lbl_ID.Text = packingIndv.packingID;
lbl_date.Text = packingIndv.date.ToString("dd/M/yyyy", CultureInfo.InvariantCulture); ;
lbl_location.Text = packingIndv.location;
lbl_volunteerAvailable.Text = packingIndv.volunteerAvailable.ToString();
lbl_status.Text = packingIndv.status;
}
}
After that, volunteers can click on the join button, and the program will execute:
In presentation layer after join button is on click:
string userLogged = Session["userLogged"].ToString();
UserBLL user = new UserBLL();
string userID = user.getUserIDByName(userLogged);
PackingBLL packing = new PackingBLL();
string msg = "";
msg = packing.joinPacking(userID, lbl_ID.Text);
lbl_msg.Text = msg;
In business logic layer:
public string joinPacking(string userID, string packingID)
{
string returnMessage = "";
if(returnMessage.Length == 0)
{
Packing packing = new Packing(userID, packingID);
Boolean success = packing.checkJoinedSession();
if (success)
{
returnMessage += "Same volunteer cannot join same packing session for more than once! <br/>";
}
else
{
int nofRows = 0;
nofRows = packing.joinPacking();
if (nofRows > 0)
{
returnMessage = "Request to volunteer for packing session saved successfully.";
int successUpdate = packing.updateRemaining();
if (successUpdate > 0)
{
getPacking(packingID);
}
}
else
{
returnMessage = "Error! Please try again.";
}
}
}
return returnMessage;
}
In data access layer:
public int updateRemaining()
{
int result = 0;
using (var connection = new SqlConnection(FFTHDb.connectionString)) // get your connection string from the other class here
{
SqlCommand command = new SqlCommand("UPDATE PackingSession SET volunteerAvailable = volunteerAvailable + 1 WHERE packingID = '" + packingID + "'", connection);
connection.Open();
result = command.ExecuteNonQuery();
connection.Close();
}
return result;
}
For every join from each volunteer, the volunteer available will be increased by one. What I am trying to do is from the page load, I display the details of packaging session. Then when volunteer joins it, the volunteerAvailable will straight away increased by one. All my database works perfectly, it just wont increase the volunteer available automatically after each successful update sql statement, as in I have to refresh the browser in order to see the changes.

Categories

Resources