In this post, part 2 of 3, we’re going to take a look at using 2 different APIs to create calendar items. The goal will be to create a web service in Visual Studio that can accept an event, and use that to create calendar events in Google, or in Outlook 365.
In the third and final installment, we will take a look at what we’ve done in parts 1&2, and use Blackbaud CRM™ as the trigger for adding events to Google and Outlook 365.

“Why do we need to have a separate web service?” you may wonder, as the Blackbaud Infinity platform allows developers to create rich customizations, and it’s certainly capable of calling external APIs. This may be true, but in reality, the APIs for Google and Outlook rely on some very specific dependencies, which will load a lot of extra components into CRM’s bin\custom directory, and may not play well either with CRM, or other customizations you will be writing. Additionally, separating the API calls into their own service allows some extra flexibility around testing, as well as the ability to be consumed by applications other than CRM.
Finally, as the Google API uses a proprietary security file, it gives administrators a little more leeway in maintaining credentials, and not have to shoehorn them into a CRM customization.
In this exercise what we’ll do is create a web service that can take a simple event with a collection of attendees, and add it to either a Google Calendar or an Outlook 365 calendar. In doing so we’ll revisit some of the Google API code we saw in Part 1, and also look at some code to work with the Outlook API.
Before you start this exercise, it’s assumed you went through part 1 and created a Google Developer’s account and project, and downloaded a .json security file to your local system. As long as you went up to the point where Part 1 discussed creating a Visual Studio project, you’ll be ok to start here. In this post, we’ll be creating a brand new VS project.
First thing is to create a new web service project:
As we saw in Part one, in order to use the Google API, we need to import some references:
Tools>NuGet Package Manager>Manage NuGet Packages for Solution
Google APIs Auth Client Library
Then do the same thing, searching for “Google.Apis.Calendar.v3 Client Library”
Rename IService1.vb and Service1.svc to ICalendarSvc.vb and CalendarSvc.scv, respectively. Then open up our interface, ICalendarSvc.vb
Now replace the default operation contracts with the following:
<OperationContract()>
Sub AddCalendarEvent(Details As EventDetails)
Next, remove the default Data Contracts and create the following, which is a new composite type. This type will be a relatively simple version of a calendar event, and is sent into our web service as the request:
<DataContract()>
Public Class EventDetails
<DataMember()>
Public Property Mode() As enumCalendarMode
<DataMember()>
Public Property EventTitle() As String
<DataMember()>
Public Property EventBody() As String
<DataMember()>
Public Property EmailAddresses() As List(Of String)
<DataMember()>
Public Property dtStart() As Date
<DataMember()>
Public Property dtEnd() As Date
End Class
The last thing we will do in this file is add an enum to tell the service what mode to use. In our example we will build in two modes – one for Google and another for Outlook365:
Public Enum enumCalendarMode As Integer
CALENDAR_MODE_GOOGLE = 0
CALENDAR_MODE_OUTLOOK = 1
End Enum
The entire file should now look like this:
<ServiceContract()>
Public Interface ICalendarSvc
<OperationContract()>
Sub AddCalendarEvent(Details As EventDetails)
End Interface
<DataContract()>
Public Class EventDetails
<DataMember()>
Public Property Mode() As enumCalendarMode
<DataMember()>
Public Property EventTitle() As String
<DataMember()>
Public Property EventBody() As String
<DataMember()>
Public Property EmailAddresses() As List(Of String)
<DataMember()>
Public Property dtStart() As Date
<DataMember()>
Public Property dtEnd() As Date
End Class
Public Enum enumCalendarMode As Integer
CALENDAR_MODE_GOOGLE = 0
CALENDAR_MODE_OUTLOOK = 1
End Enum
Open CalendarSvc.svc, remove what’s there and paste the following:
Public Class CalendarSvc
Implements ICalendarSvc
Public Sub New()
End Sub
Sub AddCalendarEvent(Details As EventDetails) Implements ICalendarSvc.AddCalendarEvent
Dim cal As ICalendarApi
If Details.Mode = enumCalendarMode.CALENDAR_MODE_GOOGLE Then
cal = New GoogleCalendarSvc
cal.AddEvent(Details)
ElseIf Details.Mode = enumCalendarMode.CALENDAR_MODE_OUTLOOK Then
cal = New Outlook365CalendarSvc
cal.AddEvent(Details)
End If
End Sub
End Class
What we’ll do next is fill in the actual code that does the work for adding the Google and Outlook events. Since the implementation is similar for both, it makes some sense to create an interface. Looking at the code above, we can infer that we’ll be making an interface called “ICalendarApi” and two classes which implement the interface: “GoogleCalendarSvc” and “Outlook365CalendarSvc”. So go ahead and create ICalendarApi, which should be very simple and look like this:
Public Interface ICalendarApi
Sub AddEvent(Details As EventDetails)
End Interface
Next, create a new class called “GoogleCalendarSvc.vb” and paste in the following:
Imports System.IO
Imports System.Threading
Imports Google.Apis.Calendar.v3
Imports Google.Apis.Calendar.v3.Data
Imports Google.Apis.Services
Imports Google.Apis.Auth.OAuth2
Imports Google.Apis.Util.Store
Imports System.Net.Http
Public Class GoogleCalendarSvc
Implements ICalendarApi
Dim _scopes As IList(Of String) = New List(Of String)()
Dim _service As Google.Apis.Calendar.v3.CalendarService
Dim _AllEvents As New List(Of Data.Event)
Dim _Details As EventDetails
Public Sub AddEvent(Details As EventDetails) Implements ICalendarApi.AddEvent
_Details = Details
InitializeService()
CreateEvent()
End Sub
Private Sub InitializeService()
_scopes.Add(Google.Apis.Calendar.v3.CalendarService.Scope.Calendar)
Dim jsonFile As String = "C:\Credentials\client_secret_791792756839-c1ev8q9gjgvep2qm1v2cl872joh2pd98.apps.googleusercontent.com.json"
Dim credential As UserCredential
Dim secrets As ClientSecrets
Dim fds As New FileDataStore("C:\Credentials", True)
Dim googleAccount As String = "brightvinesolutions@gmail.com"
Try
Using stream As New FileStream(jsonFile, FileMode.Open, FileAccess.Read)
secrets = GoogleClientSecrets.Load(stream).Secrets
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, _scopes, googleAccount, CancellationToken.None, fds).Result
End Using
Catch ex As Exception
Throw ex
End Try
' Create the calendar service using an initializer instance
Dim initializer As New BaseClientService.Initializer()
initializer.HttpClientInitializer = credential
initializer.ApplicationName = "VB.NET Calendar Sample"
_service = New Google.Apis.Calendar.v3.CalendarService(initializer)
End Sub
Private Sub CreateEvent()
Try
Dim calEvent As New Google.Apis.Calendar.v3.Data.Event
calEvent.Summary = _Details.EventTitle
calEvent.Description = _Details.EventBody
calEvent.Location = ""
Dim attendees As New List(Of EventAttendee)
Dim evAttendee As EventAttendee
For Each curAttendee As String In _Details.EmailAddresses
evAttendee = New EventAttendee
evAttendee.Email = curAttendee
attendees.Add(evAttendee)
Next
calEvent.Attendees = attendees
Dim evStart As New EventDateTime
evStart.DateTime = _Details.dtStart
Dim evEnd As New Data.EventDateTime
evEnd.DateTime = _Details.dtEnd
calEvent.Start = evStart
calEvent.End = evEnd
Dim createdEvent As [Event] = _service.Events.Insert(calEvent, "primary").Execute
Catch ex As HttpRequestException
Throw ex
Catch ex As Exception
Throw ex
End Try
End Sub
End Class
Note that in InitializeService, you’ll need to change the “dim jsonFile…” to reflect the real location of the json file you downloaded from Google. This location, of course, will need to be accessible by IIS, so make sure the AppPool you’re running under has proper rights.
At this point if we were to go back into CalendarSvc.svc and comment out the following lines: