Acessing Google Calendar API from Windows Service - vb.net

I am writing a windows service application in Visual Studio (VB) that polls a users google calendar for any events that are happening within the next 5 minutes.
Ideally, I'd like my service to generate the credentials, but I don't think a windows service can pop up a browser page to authenticate someone. Currently I am generating the credentials in a specific location from a console app that can pop up a browser, and having the service look for credentials in that location. I'd like to get rid of the console app altogether, but if it's necessary I'll just run it in the batch file that installs the service.
The big issue I'm having is generating the credentials file (secondary concern), and more importantly refreshing it so it doesn't expire after an hour (primary concern).
Here is my windows service code (this works perfectly fine for the hour after I run my console app and allow access to my calendar):
Dim Scopes As String() = {CalendarService.Scope.CalendarReadonly}
Dim ApplicationName As String = "Google Calendar API .NET Quickstart"
Private Sub writeUpdateTimerEvent(source As Object, e As ElapsedEventArgs)
Dim credential As UserCredential
Try
Using stream = New FileStream("FILE PATH TO client_secret.json", FileMode.Open, FileAccess.Read)
Dim credPath As String = "FILE PATH TO WHERE MY CONSOLE APP IS STORING THE CREDENTIALS FILE"
credPath = Path.Combine(credPath, ".credentials/calendar-dotnet-quickstart.json")
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets, Scopes, "user", CancellationToken.None, New FileDataStore(credPath, True)).Result
If credential Is Nothing Then
credential.RefreshTokenAsync(CancellationToken.None)
End If
End Using
' Create Google Calendar API service.
Dim service = New CalendarService(New BaseClientService.Initializer() With {
.HttpClientInitializer = credential,
.ApplicationName = ApplicationName
})
' Define parameters of request.
Dim request As EventsResource.ListRequest = service.Events.List("primary")
request.TimeMin = DateTime.Now
request.TimeMax = DateTime.Now.AddMinutes(5)
request.ShowDeleted = False
request.SingleEvents = True
request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime
' List events.
Dim eventsString As String = ""
Dim events As Events = request.Execute()
If events.Items IsNot Nothing AndAlso events.Items.Count > 0 Then
'This is where I do my operations on events occuring in the next 5 minutes
EventLog1.WriteEntry("Event occuring within 5 minutes")
Else
EventLog1.WriteEntry("No event occuring within 5 minutes")
End If
Catch ex As Exception
EventLog1.WriteEntry("error grabbing events." & Environment.NewLine & ex.message)
End Try
End Sub
Here is my console app code (pretty much the same as above):
Module Module1
Dim Scopes As String() = {CalendarService.Scope.CalendarReadonly}
Dim ApplicationName As String = "Google Calendar API .NET Quickstart"
Sub Main()
Dim credential As UserCredential
Using stream = New FileStream("client_secret.json", FileMode.Open, FileAccess.Read)
Dim credPath As String = "SAME FILE PATH AS IN MY SERVICE"
credPath = Path.Combine(credPath, ".credentials/calendar-dotnet-quickstart.json")
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets, Scopes, "user", CancellationToken.None, New FileDataStore(credPath, True)).Result
Console.WriteLine(Convert.ToString("Credential file saved to: ") & credPath)
End Using
' Create Google Calendar API service.
Dim service = New CalendarService(New BaseClientService.Initializer() With {
.HttpClientInitializer = credential,
.ApplicationName = ApplicationName
})
' Define parameters of request.
Dim request As EventsResource.ListRequest = 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.
Dim events As Events = request.Execute()
Console.WriteLine("Upcoming events:")
If events.Items IsNot Nothing AndAlso events.Items.Count > 0 Then
For Each eventItem As Object In events.Items
Dim [when] As String = eventItem.Start.DateTime.ToString()
If [String].IsNullOrEmpty([when]) Then
[when] = eventItem.Start.[Date]
End If
Console.WriteLine("{0} ({1})", eventItem.Summary, [when])
Next
Console.WriteLine("You may now close this window.")
System.Environment.Exit(0)
Else
Console.WriteLine("No upcoming events found.")
End If
Console.Read()
End Sub
End Module

Got it working now, using a service account instead of a user account. No need for dealing with generating credentials or refreshing the token.
Dim serviceAccountEmail As [String] = ConfigurationManager.AppSettings("ServiceAcct")
Dim certificate = New X509Certificate2("key.p12", "notasecret", X509KeyStorageFlags.Exportable)
Dim credential1 As New ServiceAccountCredential(New ServiceAccountCredential.Initializer(serviceAccountEmail) With {
.Scopes = Scopes
}.FromCertificate(certificate))
Dim service = New CalendarService(New BaseClientService.Initializer() With {
.HttpClientInitializer = credential1,
.ApplicationName = ApplicationName
})

Related

Oauth 2.0 SMTP send email with EASendEmail VB

Following the changes, I try to connect and send mails via EAGetMail/EASendMail.
The connection is good, I have good access to the token and also to my mailbox.
However, when I want to send an email via "smtp.office365.com" I get an error: 535 5.7.3 Authentication unsuccessful.
I do not understand where the error can come from, I take the same token as when connecting to the mailbox.
Below is just the code to send emails, I have a token and it works perfectly to connect to my email
If someone has a project that works with smtp and Oauth 2.0 (without using a browser)...
Module Module1
Sub Main(ByVal args As String())
Try
RetrieveEmail()
Catch ep As Exception
Console.WriteLine(ep.ToString())
End Try
Console.ReadKey()
End Sub
Function _generateFileName(ByVal sequence As Integer) As String
Dim currentDateTime As DateTime = DateTime.Now
Return String.Format("{0}-{1:000}-{2:000}.eml",
currentDateTime.ToString("yyyyMMddHHmmss", New CultureInfo("en-US")),
currentDateTime.Millisecond,
sequence)
End Function
Function _postString(ByVal uri As String, ByVal requestData As String) As String
Dim httpRequest As HttpWebRequest = TryCast(WebRequest.Create(uri), HttpWebRequest)
httpRequest.Method = "POST"
httpRequest.ContentType = "application/x-www-form-urlencoded"
Using requestStream As Stream = httpRequest.GetRequestStream()
Dim requestBuffer As Byte() = Encoding.UTF8.GetBytes(requestData)
requestStream.Write(requestBuffer, 0, requestBuffer.Length)
requestStream.Close()
End Using
Try
Dim httpResponse As HttpWebResponse = TryCast(httpRequest.GetResponse(), HttpWebResponse)
Using reader As New StreamReader(httpResponse.GetResponseStream())
Dim responseText = reader.ReadToEnd()
Return responseText
End Using
Catch ex As WebException
If ex.Status = WebExceptionStatus.ProtocolError Then
Dim response = TryCast(ex.Response, HttpWebResponse)
If response IsNot Nothing Then
Console.WriteLine("HTTP: " & response.StatusCode)
' reads response body
Using reader As StreamReader = New StreamReader(response.GetResponseStream())
Dim responseText As String = reader.ReadToEnd()
Console.WriteLine(responseText)
End Using
End If
End If
Throw ex
End Try
End Function
Public Sub RetrieveEmail()
Try
Dim client_id As String = "XXXXXXXXXXXXXXXXXXXX"
Dim client_secret As String = "XXXXXXXXXXXXXXXXXXXXXXXXX"
' If your application is not created by Office365 administrator,
' please use Office365 directory tenant id, you should ask Offic365 administrator to send it to you.
' Office365 administrator can query tenant id in https://portal.azure.com/ - Azure Active Directory.
Dim tenant As String = "XXXXXXXXXXXXXXXXXX"
Dim requestData As String = String.Format("client_id={0}&client_secret={1}&scope=https://outlook.office365.com/.default&grant_type=client_credentials",
client_id, client_secret)
Dim tokenUri As String = String.Format("https://login.microsoftonline.com/{0}/oauth2/v2.0/token", tenant)
Dim responseText As String = _postString(tokenUri, requestData)
Dim parser As EASendMail.OAuthResponseParser = New EASendMail.OAuthResponseParser()
parser.Load(responseText)
Dim officeUser As String = "tma#XXXX.fr"
Dim oServerSend As SmtpServer = New SmtpServer("smtp.office365.com")
oServerSend.ConnectType = SmtpConnectType.ConnectSSLAuto
oServerSend.Port = 587
oServerSend.AuthType = SmtpAuthType.XOAUTH2
oServerSend.User = officeUser
oServerSend.Password = parser.AccessToken
Dim oMailSend As SmtpMail = New SmtpMail("TryIt")
oMailSend.From = "tma#XXX.fr"
' Please change recipient address to yours for test
oMailSend.[To] = "XXXXXXXXXXX"
oMailSend.Subject = "test email from Hotmail account with OAUTH 2"
oMailSend.TextBody = "this is a test email sent from VB.NET project with Hotmail."
Console.WriteLine("start to send email using OAUTH 2.0 ...")
Dim oSmtp As SmtpClient = New SmtpClient()
oSmtp.SendMail(oServerSend, oMailSend)
' Quit and expunge emails marked as deleted from server.
Console.WriteLine("Completed!")
Catch ep As Exception
Console.WriteLine(ep.ToString())
End Try
End Sub
End Module

VB.NET Crawler can't handle Single Page Applications such as AngularJS

I have an existing web crawler (WinForms) developed using VB.NET for our SEOs which utilizes Web Requests. The application works fine on a regular website but when I try to crawl SPA sites (Single Page Applications), the application can't get a proper response.
Dim siteBody As String = String.Empty
Dim cleanedURL As String
Dim wRequest As System.Net.HttpwRequestuest
Dim wResponse As System.Net.HttpwResponse
Dim rStream As System.IO.Stream
Dim reader As System.IO.StreamReader
Try
wRequest = Nothing
wResponse = Nothing
rStream = Nothing
wRequest = HttpwRequestuest.Create(urlList(i)) 'URL is being passed
wRequest.Credentials = System.Net.CredentialCache.DefaultCredentials
wRequest.UserAgent = "DummyValue"
wRequest.AllowAutoRedirect = False
wResponse = wRequest.GetResponse()
rStream = wResponse.GetResponseStream
reader = New System.IO.StreamReader(rStream)
siteBody = reader.ReadToEnd
reader.Close()
wResponse.Close()
Catch ex As Exception
End Try
Dim passedBody = siteBody 'EMPTY RESULT
Based on the result, we will extract data and check for links and their status codes.

method not found Google.apis.Calendar.v3.CalendarService..ctor(Initializer)

I have a VB NET application that works correctly in the development environment(windows 8.1).
When I distributed to a computer with windows 7 operates properly.
But when distributed to a computer with Windows 10 I get this error.
Method not found: Void
Google.apis.Calendar.v3.CalendarService..ctor(Initializer).
The procedure that gives me error is as follows:
Try
Dim scopes As IList(Of String) = New List(Of String)()
scopes.Add(CalendarService.Scope.Calendar)
Dim credential As UserCredential
Dim cs As New ClientSecrets
cs.ClientId = wclientId
cs.ClientSecret = wclientSecret
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(cs, scopes, "user", CancellationToken.None).Result
Dim initializer As New BaseClientService.Initializer()
initializer.HttpClientInitializer = credential
initializer.ApplicationName = wapplicationName
service = New CalendarService(initializer)
clientIdAutenticado = wclientId
Catch ex As Exception
Throw New Exception("autenticate:" & ex.Message & ":" & ex.StackTrace)
End Try

Connecting a VB.NET application with a Google Docs Spreadsheet

I'm creating a small application that can order stuff. The way a user can order something is to input the correct information through a google form, which then would be automatically converted to a Google Spreadsheet.
Now, I want to connect it to my VB application. How can I do that?
You should install sheetsapi v4 to your app.
Here is the code:
Public Class Form3
Shared Scopes As String() = {SheetsService.Scope.SpreadsheetsReadonly}
Shared ApplicationName As String = "Google Sheets API .NET Quickstart"
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim credential As UserCredential
Using stream = New FileStream("client_secret.json", FileMode.Open, FileAccess.Read)
Dim credPath As String = 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(Convert.ToString("Credential file saved to: ") & credPath)
End Using
Dim service = New SheetsService(New BaseClientService.Initializer() With { _
.HttpClientInitializer = credential, _
.ApplicationName = ApplicationName })
Dim spreadsheetId As [String] = "your sheet id"
Dim range As [String] = "A2:F"
Dim request As SpreadsheetsResource.ValuesResource.GetRequest = service.Spreadsheets.Values.[Get](spreadsheetId, range)
Dim response As ValueRange = request.Execute()
Dim values As IList(Of IList(Of [Object])) = response.Values
Dim son As String
If values IsNot Nothing AndAlso values.Count > 0 Then
ListBox1.Items.Add("Name, Major")
For Each rol In values
son = rol(0) + " " + rol(1) + " " + rol(2) + " " + rol(4)
' Print columns A and E, which correspond to indices 0 and 4.
ListBox1.Items.Add(son)
Next
End If
End Sub
End Class

Dropnet code in vb not working

I'm trying to use dropnet for file upload on Dropbox in vb, but does not work. Results the following error: Received Response [Unauthorized]: Expected to see [OK]. The HTTP response was [{"error": "Request token not found."}]
Here is my code:
_client = New DropNetClient("xxxxxxx", "xxxxxxx")
Dim login As UserLogin = _client.GetToken()
_client.UserLogin = login
Dim url = _client.BuildAuthorizeUrl()
Process.Start(url)
Dim tokenAcess = _client.GetAccessToken()
_client.GetAccessTokenAsync(Function(accessToken)
_client = New DropNetClient("xxxxxx", "xxxxxx", tokenAcess)
End Function, Function([error]) MessageBox.Show([error].Message)
End Function)
Try
Dim rawData As Byte() = File.ReadAllBytes("c:\image.png")
Dim result As MetaData = _client.UploadFile("/", "image.png", rawData)
MessageBox.Show("Successfully uploaded to Dropbox.", "Uploaded to Dropbox")
Catch dropboxEx As Exception
MessageBox.Show("Error: " + dropboxEx.Message)
End Try