I know this question was answered some time ago, however I thought this would be a good place to share my findings for those having similar difficulty finding examples. I have found it to be difficult to find documentation/samples on using the Google APIs .Net library for an Desktop or MVC Web application. I finally found a good example in the tasks example you can find in the samples repository on the Google Project site here <- That really really helped me out.
I ended up snagging the source for the FileDataStore and created an AppDataStore class and placed it in my App_Code folder. You can find the source here, though it was a simple change really - changing the folder to point to ~/App_Data instead.
The last piece of the puzzle I'm looking into figuring out is getting the offline_access token.
Edit: Here's the code for convenience:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Util.Store;
using Google.Apis.Json;
namespace Google.Apis.Util.Store {
public class AppDataFileStore : IDataStore {
readonly string folderPath;
/// <summary>Gets the full folder path.</summary>
public string FolderPath { get { return folderPath; } }
/// <summary>
/// Constructs a new file data store with the specified folder. This folder is created (if it doesn't exist
/// yet) under <see cref="Environment.SpecialFolder.ApplicationData"/>.
/// </summary>
/// <param name="folder">Folder name.</param>
public AppDataFileStore(string folder) {
folderPath = Path.Combine(HttpContext.Current.Server.MapPath("~/App_Data/"), folder);
if (!Directory.Exists(folderPath)) {
Directory.CreateDirectory(folderPath);
}
}
/// <summary>
/// Stores the given value for the given key. It creates a new file (named <see cref="GenerateStoredKey"/>) in
/// <see cref="FolderPath"/>.
/// </summary>
/// <typeparam name="T">The type to store in the data store.</typeparam>
/// <param name="key">The key.</param>
/// <param name="value">The value to store in the data store.</param>
public Task StoreAsync<T>(string key, T value) {
if (string.IsNullOrEmpty(key)) {
throw new ArgumentException("Key MUST have a value");
}
var serialized = NewtonsoftJsonSerializer.Instance.Serialize(value);
var filePath = Path.Combine(folderPath, GenerateStoredKey(key, typeof(T)));
File.WriteAllText(filePath, serialized);
return TaskEx.Delay(0);
}
/// <summary>
/// Deletes the given key. It deletes the <see cref="GenerateStoredKey"/> named file in
/// <see cref="FolderPath"/>.
/// </summary>
/// <param name="key">The key to delete from the data store.</param>
public Task DeleteAsync<T>(string key) {
if (string.IsNullOrEmpty(key)) {
throw new ArgumentException("Key MUST have a value");
}
var filePath = Path.Combine(folderPath, GenerateStoredKey(key, typeof(T)));
if (File.Exists(filePath)) {
File.Delete(filePath);
}
return TaskEx.Delay(0);
}
/// <summary>
/// Returns the stored value for the given key or <c>null</c> if the matching file (<see cref="GenerateStoredKey"/>
/// in <see cref="FolderPath"/> doesn't exist.
/// </summary>
/// <typeparam name="T">The type to retrieve.</typeparam>
/// <param name="key">The key to retrieve from the data store.</param>
/// <returns>The stored object.</returns>
public Task<T> GetAsync<T>(string key) {
if (string.IsNullOrEmpty(key)) {
throw new ArgumentException("Key MUST have a value");
}
TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
var filePath = Path.Combine(folderPath, GenerateStoredKey(key, typeof(T)));
if (File.Exists(filePath)) {
try {
var obj = File.ReadAllText(filePath);
tcs.SetResult(NewtonsoftJsonSerializer.Instance.Deserialize<T>(obj));
}
catch (Exception ex) {
tcs.SetException(ex);
}
}
else {
tcs.SetResult(default(T));
}
return tcs.Task;
}
/// <summary>
/// Clears all values in the data store. This method deletes all files in <see cref="FolderPath"/>.
/// </summary>
public Task ClearAsync() {
if (Directory.Exists(folderPath)) {
Directory.Delete(folderPath, true);
Directory.CreateDirectory(folderPath);
}
return TaskEx.Delay(0);
}
/// <summary>Creates a unique stored key based on the key and the class type.</summary>
/// <param name="key">The object key.</param>
/// <param name="t">The type to store or retrieve.</param>
public static string GenerateStoredKey(string key, Type t) {
return string.Format("{0}-{1}", t.FullName, key);
}
}
}
I had to set the approval prompt to force in order to get the offline access token.
var req = HttpContext.Current.Request;
var oAuthUrl = Flow.CreateAuthorizationCodeRequest(new UriBuilder(req.Url.Scheme, req.Url.Host, req.Url.Port, GoogleCalendarUtil.CallbackUrl).Uri.ToString()) as GoogleAuthorizationCodeRequestUrl;
oAuthUrl.Scope = string.Join(" ", new[] { CalendarService.Scope.CalendarReadonly });
oAuthUrl.ApprovalPrompt = "force";
oAuthUrl.State = AuthState;