Google calendar event list is empty - c#

Here is my code:
using System;
using System.Net;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
using Google.Apis.Services;
using Google.Apis.Auth.OAuth2;
using System.Threading;
using System.Linq;
namespace WebsiteTextExtractor {
class Program {
async static Task Main(string[] args) {
string websiteURL = "CensoredURLThatWorks";
WebClient client = new WebClient();
string websiteText = client.DownloadString(websiteURL);
//File.WriteAllText(Environment.GetFolderPath(Environment.SpecialFolder.Desktop)+ "\\ElieCours.ics", websiteText);
// Console.WriteLine($"ElieCours.ics Updated at {Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\ElieCours.ics"}.");
string[] scopes = new string[] { CalendarService.Scope.Calendar };
var credentials = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets {
ClientId = "[redacted]",
ClientSecret = "[redacted]"
},
scopes,
"MyClient",
CancellationToken.None
).Result;
var service = new CalendarService(new BaseClientService.Initializer() {
HttpClientInitializer = credentials,
ApplicationName = "CalendarCleaner"
});
var events = service.Events.List("fc47dab8b05e7b6d0e549ff3207b9f400adfb8ff96b50ecc4ed51a9ecc75ebbe#group.calendar.google.com").Execute().Items;
//Deleting all events
ParallelOptions parallel = new() {
MaxDegreeOfParallelism = 3,
};
Console.WriteLine(events.Count);
await Parallel.ForEachAsync(events, parallel, async (ev, token) => {
await Task.Delay(300, token);
await service.Events.Delete("fc47dab8b05e7b6d0e549ff3207b9f400adfb8ff96b50ecc4ed51a9ecc75ebbe#group.calendar.google.com", ev.Id).ExecuteAsync(token);
});
Ical.Net.Calendar calendarICS = Ical.Net.Calendar.Load(websiteText);
var eventsICS = calendarICS.Events;
await Parallel.ForEachAsync(eventsICS, parallel, async (ev, token) => {
Event newEvent = new() {
Summary = ev.Summary,
Start = new EventDateTime { DateTime = ev.Start.AsSystemLocal },
End = new EventDateTime { DateTime = ev.End.AsSystemLocal },
Description = ev.Description,
};
await Task.Delay(300, token);
await service.Events.Insert(newEvent, "fc47dab8b05e7b6d0e549ff3207b9f400adfb8ff96b50ecc4ed51a9ecc75ebbe#group.calendar.google.com").ExecuteAsync(token);
});
}
}
}
the part where i'm supposed to be getting the events that are in the "events" var is troubling me: the array is empty. But the adding events part just below is working perfectly. Why?
I saw this post: Google Calendar Events Response is Empty
and i was even more confused, because my methods has nothing to do with what they have.
i tried adding a service account, freshly created, to my agenda: nothing. Making my agenda public: nothing. Whatever i do, this array is empty. Best thing is that it wasn't earlier this morning, and now it is. And i know this might be dumb to specify, but i triplechecked my agenda, and it's not empty.
Worst thing is : deleting used to work.
EDIT: saw this post: Google Calendar v3 API [Events: list] request return Empty List
An answer was really interesting... Detailed the way google doesn't really deleted the events or so...? I'm so confused.
"There is no way I know of to return all events in one call. You need to loop through the process getting a page at a time until the "NextPageToken" is no longer returned. This makes sense, because for users that have huge calendars with 1000's of appointments, it's inefficient to return everything in one request." Even more here, never heard of nextpagetoken or so

Related

How to stop a Httpclient in c#

In my wpf project I have this:
private async void RequestStart(HttpClient client, Task task)
{
NetworkModel nmodel = new NetworkModel();
NetworkModel1.Rootobject tryModel = await nmodel.ClientStock();
var apiClient = new APIClient();
Task<string> getResponseColourSize = apiClient.GetAsync($"https://www.try.com/{id}.json");
var ATCvalues = new Dictionary<string, string>
{
{ "style", sizeColourID.colourID.ToString() },
{ "size", sizeColourID.sizeID.ToString() },
};
var ATCcontent = new FormUrlEncodedContent(ATCvalues);
var ATCresponse = await client.PostAsync($"https://www.try.com/{id}/cart.json", ATCcontent);
var ATCresponseString = await ATCresponse.Content.ReadAsStringAsync();
System.Windows.MessageBox.Show(ATCresponseString);
}
Firstly I make a GET request and then after several other GET requests, I make a POST request
How would I be able to make it so that on a button click the user would be able to stop the request. The problem is that I cannot find something online to satisfy this. The only things I have found are for either GET or POST requests. Would I just need to stop the RequestStart altogether? Any help would be appreciated!

Microsoft Graph API call hangs indefinitely

I am attempting to query Azure Active Directory User information using Microsoft Graph. I can authenticate fine but when I attempt to query user information client.Users my application hangs indefinitely: no timeout, no error, just hangs. I found this post however the suggestions there did not help me.
public bool GetUserByUniqueID(string uid, out GraphUser user)
{
bool ret = false;
user = new GraphUser();
if (Authenticate(out AuthToken token))
{
GraphServiceClient client = GetGraphServiceClient(token);
// The below code hangs indefinitely
User user = client.Users[uid].Request().Select(GraphProperties).GetAsync().GetAwaiter().GetResult();
if (user != null)
{
MapGraphUser(ret, user);
ret = true;
}
}
return ret;
}
private bool Authenticate(out AuthToken token)
{
bool ret = false;
token = new AuthToken();
string url = $"https://login.microsoftonline.com/{_tenant}/oauth2/v2.0/token";
RestClient client = new RestClient(url);
RestRequest request = new RestRequest(Method.POST);
request.Parameters.Add(new Parameter("grant_type", _grantType, ParameterType.GetOrPost));
request.Parameters.Add(new Parameter("scope", _scope, ParameterType.GetOrPost));
request.Parameters.Add(new Parameter("client_secret", _clientSecret, ParameterType.GetOrPost));
request.Parameters.Add(new Parameter("client_id", _clientId, ParameterType.GetOrPost));
IRestResponse response = client.Execute<AuthToken>(request);
if (response.StatusCode == HttpStatusCode.OK)
{
token = JsonConvert.DeserializeObject<AuthToken>(response.Content);
ret = true;
}
return ret;
}
Update 5/2/2019
Reverting Microsoft.Graph and Microsoft.Graph.Core to version 1.12 allows me to call .GetAwaiter().GetResult() within a synchronous context.
Update 11/18/2020
I have refactored my code to use async/await pattern with the latest version of Microsoft.Graph and Microsoft.Graph.Core.
public async Task<GraphUser> GetUserByUniqueID(string uid)
{
GraphUser ret = new GraphUser();
if (Authenticate(out AuthToken token))
{
GraphServiceClient client = GetGraphServiceClient(token);
User user = await client.Users[uid].Request().Select(GraphProperties).GetAsync();
if (user != null)
{
MapGraphUser(ret, user);
ret.Found = true;
}
}
return ret;
}
I was having the same issue. I found on another article somewhere that it had something to do with two task waiting to finish at once. i cant find that article now.
For me .GetAwaiter().GetResult(); was working within a scheduled job but not as a manual button press task.
as a result of playing around with it. What worked for me was replacing .GetAwaiter().GetResult() with await. (i'm not sure why this fixed it but it did)
From:
var results = graphServiceClient.Users[uid].Request().GetAsync().GetAwaiter().GetResult();
To:
var results = await graphServiceClient.Users[uid].Request().GetAsync();
Hope this helps someone in the future
I'm having the same issue with NPM package of the Graph API. Reverted to plain old request-promise. Now it's not stuck but does not always find the members of a group. Using beta version of the API works fine
I had the same issue when trying to get a list of sites, but I was using Microsoft.Graph V 4.47.0 and Microsoft.Graph.Core V 2.0.14, from within a MVC Web project. I was also using await.
var drives = await graphClient.Sites["root"].Lists
.Request()
.GetAsync();
The above just hangs. Changing to:
var drives = graphClient.Sites["root"].Lists
.Request()
.GetAsync()
.GetAwaiter()
.GetResult();
works as expected.
Full Code:
public async Task GetDrives(GraphServiceClient graphClient)
{
AuthenticationConfig config = AuthenticationConfig.ReadFromJsonFile("appsettings.json");
O365Drives = new List<MyDriveInfo>();
var drives = graphClient.Sites["root"].Lists
.Request()
.GetAsync()
.GetAwaiter()
.GetResult();
foreach (var item in drives)
{
O365Drives.Add(new MyDriveInfo
{
Id = item.Id,
Name = item.Name,
WebUrl = item.WebUrl,
CreatedOn = item.CreatedDateTime,
ModifiedOn = item.LastModifiedDateTime
});
}
}
The above is called by firing an Ajax POST request when clicking on a button.
In another project, a console app, using Microsoft.Graph V 4.34.0 and Microsoft.Graph.Core V 2.0.9
var drives = await graphClient.Sites["root"].Lists
.Request()
.GetAsync();
Works as expected.
Full Code:
private static async Task GetDrives(GraphServiceClient graphClient)
{
AuthenticationConfig config = AuthenticationConfig.ReadFromJsonFile("appsettings.json");
myFileInfo.O365Drives = new List<MyDriveInfo>();
var drives = await graphClient.Sites[$"{config.SiteID}"].Lists
.Request()
.GetAsync();
foreach(var item in drives)
{
myFileInfo.O365Drives.Add(new MyDriveInfo
{
Id = item.Id,
Name = item.Name,
WebUrl = item.WebUrl,
CreatedOn = item.CreatedDateTime,
ModifiedOn = item.LastModifiedDateTime
});
}
}
The above is called by either running the console app manually or from a scheduled task.
I just thought I'd post my findings for the newer versions of Microsoft.Graph for anyone else having similar issues.

ClaimsPrincipal.Current.Identity.Name Empty when authenticated from client, fine in browser

I have the following Azure Function,
#r "Newtonsoft.Json"
using Newtonsoft.Json.Linq;
using System.Net;
using System.Security.Claims;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
try
{
JObject pJOtClaims = new JObject();
foreach(Claim curClaim in ClaimsPrincipal.Current.Identities.First().Claims)
{
pJOtClaims.Add(curClaim.Type, new JValue(curClaim.Value));
}
return(req.CreateResponse(HttpStatusCode.OK, $"{pJOtClaims.ToString(Newtonsoft.Json.Formatting.None)}"));
}
catch(Exception ex)
{
return(req.CreateResponse(HttpStatusCode.OK, $"{ex.Message}"));
}
}
I have configured only Facebook authentication for this Function App. This function works for both in-browser and client authentication. When I invoke this method in browser I get a whole bunch of claims, including my registered Facebook email address. When I invoke this from client authentication, I get the following claims,
{
"stable_sid":"...",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier":"...",
"http://schemas.microsoft.com/identity/claims/identityprovider":"...",
"ver":"...",
"iss":"...",
"aud":"...",
"exp":"...",
"nbf":"..."
}
Unfortunately none of these include my Facebook email address which I need. I have enabled the "email" scope for the Facebook authentication configuration. Any ideas how to get this?
Nick.
Okay so I haven't found the exact solution I wanted, but this should get me by. Technically I only need the email address during registration, after that I can just use the stable_sid as is part of the identity I do get. So What I have done is to pass on the x-zumo-auth header to the ".auth/me" method, get the property I need. I'm using this method
public static async Task<String> GetAuthProviderParam(String iAuthMeURL,
String iXZumoAUth,
String iParamKey)
{
using (HttpClient pHCtClient = new HttpClient())
{
pHCtClient.DefaultRequestHeaders.Add("x-zumo-auth", iXZumoAUth);
String pStrResponse = await pHCtClient.GetStringAsync(iAuthMeURL);
JObject pJOtResponse = JObject.Parse(pStrResponse.Trim(new Char[] { '[', ']' }));
if(pJOtResponse[iParamKey] != null)
{
return (pJOtResponse[iParamKey].Value<String>());
}
else
{
throw new KeyNotFoundException(String.Format("A parameter with the key '{0}' was not found.", iParamKey));
}
}
}
This can be called in the function like so,
if(req.Headers.Contains("x-zumo-auth"))
{
String pStrXZumoAuth = req.Headers.GetValues("x-zumo-auth").First();
String pStrParam = await FunctionsHelpers.GetAuthProviderParam("https://appname.azurewebsites.net/.auth/me",
pStrXZumoAuth,
"user_id");
//pStrParam = user_id
}

HttpClient (Windows.Web.Http) working with cookies

I am working on a Windows app and am having some issues with cookies. Please note that I am working with Windows.Web.Http, not the System namespace HttpClient.
The API I'm working with uses an auth-header for authentication. Basically after a POST to login, I need a way to get the cookies returned and then use those cookies to perform the subsequent API calls. I posted an example of what I currently have, which succeeds. I can see the cookies in the result object. I'm just not entirely sure where to go from here / how to proceed. Thanks! Any ideas?
using MyApi.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Web.Http;
using Newtonsoft.Json;
using MyApi.Models.Auth;
using MyApi.Models;
namespace MyApi
{
public class MyService
{
private const string MyBaseUrl = "http://api.my.com:3000";
private readonly HttpClient _httpClient = new HttpClient();
public async Task<SignInResponse> AttemptLogin(string username, string password)
{
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
throw new ArgumentException("Username or password is null or empty");
var uri = new Uri(string.Format("{0}/{1}", MyBaseUrl, "auth/signin"));
var authSignIn = new Models.Auth.SignInRequest();
authSignIn.Email = username;
authSignIn.Password = password;
var myObject = JsonConvert.SerializeObject(authSignIn);
// I see the headers in the result object, but I'm not
// sure the best way to a) get them out and b) shove them into
// all of the next calls
var result = await _httpClient.PostAsync(uri,
new HttpStringContent(myObject.ToString(),
Windows.Storage.Streams.UnicodeEncoding.Utf8,
"application/json"));
var content = await result.Content.ReadAsStringAsync();
var successResponse = new SignInResponse();
try
{
successResponse = JsonConvert.DeserializeObject<SignInResponse>(content);
}
catch (Exception)
{
var failResponse = JsonConvert.DeserializeObject<ErrorResponse>(content);
throw new Exception(failResponse.message);
}
return successResponse;
}
}
}
You can use HttpBaseProtocolFilter.CookieManager, e.g.:
var filter = new HttpBaseProtocolFilter();
var cookieManager = filter.CookieManager;
var uri = new Uri("http://api.my.com:3000");
foreach (var cookie in cookieManager.GetCookies(uri))
{
Debug.WriteLine(cookie.Name);
Debug.WriteLine(cookie.Value);
}
Notice, if the cookies are already in the HttpCookieContainer, the cookies will be automatically added in the next requests to http://api.my.com:3000, and no action is required from your side.
If you want to modify them or delete them, the HttpCookieContainer has methods to do that.
Take a look at Flurl. It presents a fluent interface over the Http bits, so you can say something like this to authenticate and reuse the connection with the cookies:
using (var fc = new FlurlClient().EnableCookies())
{
var url = new Url( "http://api.com/endpoint" ) ;
await url
.AppendPathSegment("login")
.WithClient(fc)
.PostUrlEncodedAsync(new { user = "user", pass = "pass" });
var page = await url
.AppendPathSegment("home")
.WithClient(fc)
.GetStringAsync();
// Need to inspect the cookies? FlurlClient exposes them as a dictionary.
var sessionId = fc.Cookies["session_id"].Value;
}

How to create VMs using google compute engine REST API

I am new to Google Compute Engine. Some one please help me with creating Google Compute Engine VMs programmatically using REST APIs in C#.
Here [1] you can found the API documentation to create an instance and at the bottom of the document the C# examples [2]:
using Google.Apis.Auth.OAuth2;
using Google.Apis.Compute.v1;
using Google.Apis.Services;
using Newtonsoft.Json;
using System;
using System.Threading.Tasks;
using Data = Google.Apis.Compute.v1.Data;
namespace ComputeSample
{
public class ComputeExample
{
public static void Main(string[] args)
{
ComputeService computeService = new ComputeService(new BaseClientService.Initializer
{
HttpClientInitializer = GetCredential(),
ApplicationName = "Google-ComputeSample/0.1",
});
// Project ID for this request.
string project = "my-project"; // TODO: Update placeholder value.
// The name of the zone for this request.
string zone = "my-zone"; // TODO: Update placeholder value.
// TODO: Assign values to desired properties of `requestBody`:
Data.Instance requestBody = new Data.Instance();
InstancesResource.InsertRequest request = computeService.Instances.Insert(requestBody, project, zone);
// To execute asynchronously in an async method, replace `request.Execute()` as shown:
Data.Operation response = request.Execute();
// Data.Operation response = await request.ExecuteAsync();
// TODO: Change code below to process the `response` object:
Console.WriteLine(JsonConvert.SerializeObject(response));
}
public static GoogleCredential GetCredential()
{
GoogleCredential credential = Task.Run(() => GoogleCredential.GetApplicationDefaultAsync()).Result;
if (credential.IsCreateScopedRequired)
{
credential = credential.CreateScoped("https://www.googleapis.com/auth/cloud-platform");
}
return credential;
}
}
}
[1] https://cloud.google.com/compute/docs/reference/rest/v1/instances/insert
[2] https://cloud.google.com/compute/docs/reference/rest/v1/instances/insert#examples

Categories