c# retrieve google agenda when an updat happens - c#

how can i get a signal that my external agenda in my own app needs to be updated when there is a new event been made. at this moment my code looks like this but i can't retrieve a new event from google calendar. what do i do wrong.
public async Task<List<EventModel>> GetAllEventsAsync()
{
var refresToken = RetrieveRefreshTokenAndRevoke.RefreshToken();
if (refresToken == "ok")
{
var tokens = JObject.Parse(System.IO.File.ReadAllText(ConstantJsonFileLink.TOKEN));
RestClient restClient = new RestClient(new Uri("https://www.googleapis.com/calendar/v3/calendars/primary/events"));
RestRequest restRequest = new RestRequest(Method.GET);
restRequest.AddQueryParameter("key", $"{ApiKey}");
restRequest.AddHeader("Authorization", "Bearer " + tokens["access_token"]);
restRequest.AddHeader("Accept", "application/json");
try
{
var response = await restClient.ExecuteAsync(restRequest);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
JObject calendarEvents = JObject.Parse(response.Content);
var allEvents = calendarEvents["items"].ToObject<List<EventModel>>();
return allEvents;
}
}
catch (Exception ex)
{
throw new Exception("Coulden't connect to google agenda.");
}
}
return null;
}

There are two ways to find out if there were changes to any events in your google calendar.
The first and less robust solution woudl be polling. You could run an events.list every five minutes or so and check for changes.
The second option would be to listen for changes by setting up a watch and listing for push notifications the way this works is you set up a web end point on your system that listens for calls from Google calendar. In the event a change is made to any of your events Google will notify this endpoint on your server and you will then know that you need to make a new call to the api to get any updates.

public Watch WatchEventAsync()
{
var refresToken = RetrieveRefreshTokenAndRevoke.RefreshToken();
if (refresToken == "ok")
{
var tokens = JObject.Parse(System.IO.File.ReadAllText(ConstantJsonFileLink.TOKEN));
var restClient = new RestClient();
var restRequest = new RestRequest();
restClient.BaseUrl = new System.Uri("https://www.googleapis.com/calendar/v3/calendars/Primary/events/watch");
Watch watch = new Watch();
watch.Id = CalendarId;
watch.Token = refresToken;
watch.Type = "webhook";
watch.Params = new Watch.Param { Ttl = "604800" };
var model = JsonConvert.SerializeObject(watch, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
restRequest.AddQueryParameter("key", $"{ApiKeys}");
restRequest.AddHeader("Authorization", "Bearer " + tokens["access_token"]);
restRequest.AddHeader("Accept", "application/json");
restRequest.AddHeader("Content-Type", "application/json; charset=utf-8");
restRequest.AddParameter("application/json", model, ParameterType.RequestBody);
try
{
var restResponse = restClient.Post(restRequest);
if (restResponse.StatusCode == System.Net.HttpStatusCode.OK)
{
JObject watchEvents = JObject.Parse(restResponse.Content);
return watchEvents.ToObject<Watch>();
}
}
catch (Exception ex)
{
throw new Exception("Coulden't Create an event in google agenda.");
}
}
return null;
}
// I have this for the moment

Related

c# Background Task only runs 1 time?

Hi so i wane do a background task with my code but the code only runs 1 time when i startup my application. i have put a break point already in my infinity loop but that doesn't get triggerd. So i was wondering what can be the issue. my task is doing a test if my data is coming in my google calendar. Its a check. I hope somebody can help me out.
protected async override Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
string DbConnectionString = _configuration.GetValue<string>("Site:ConnectionString");
using (IDbConnection conn = OpenConnection(DbConnectionString))
{
List<GoogleAccess> googleCredentials = conn.Query<Domain.GoogleAccess>("Select g.Id, g.CalendarId, g.RefreshToken, convert(nvarchar(36), g.CompanyUserId) as CompanyUserId from [dbo].[googleAccess] g", null, commandType: CommandType.Text).ToList();
// list with all users
foreach (var credential in googleCredentials.Where(e => e.RefreshToken is not null).ToList())
{
var accessToken = RefreshToken(credential.RefreshToken);
// search all events Where that contain CompanyUserTreatmentId From that user
var allReservations = await TurnUp.Admin.Infrastructure.RestAPI.Reservation.GetAll(new Models.RestAPI.Reservation.PostModel.GetAllReservationPostModel() { });
var covertedList = new List<EventModel>();
foreach (var reservation in allReservations.result.items.Where(e => e.isCancelled == false).ToList())
{
covertedList.Add(new EventModel
{
Id = reservation.id.ToString(),
Description = reservation.description,
Start = new EventDateTime { DateTime = DateTime.Parse(reservation.startTime.ToString()).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK"), TimeZone = "Europe/Zurich" },
End = new EventDateTime { DateTime = DateTime.Parse(reservation.endTime.ToString()).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK"), TimeZone = "Europe/Zurich" },
Summary = reservation.description
});
}
//Retrieving all Google Events from google api
var allGoogleEvents = new List<EventModel>();
RestClient restClient = new RestClient(new Uri("https://www.googleapis.com/calendar/v3/calendars/primary/events"));
RestRequest restRequest = new RestRequest();
//Send parameters with the request
restRequest.AddQueryParameter("key", $"{ApiKeys}");
restRequest.AddParameter("maxResults", 2500);
restRequest.AddParameter("OrderBy", "startTime");
restRequest.AddParameter("showDeleted", "false");
restRequest.AddParameter("timeMin", DateTime.UtcNow.AddMonths(-1).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK"));
restRequest.AddParameter("timeMax", DateTime.UtcNow.AddMonths(6).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK"));
restRequest.AddHeader("Authorization", "Bearer " + accessToken);
restRequest.AddHeader("Accept", "application/json");
try
{
//Get request to server
var response = restClient.Get(restRequest);
//check if response is ok
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
//change response to an class that can be used
JObject calendarEvents = JObject.Parse(response.Content);
var test = calendarEvents["nextSyncToken"].ToString();
allGoogleEvents = calendarEvents["items"].ToObject<List<EventModel>>();
}
}
catch (Exception ex)
{
throw new Exception("Coulden't connect to google agenda.");
}
//list with reservations that arn't in google
var newList = covertedList.Except(allGoogleEvents).Concat(allGoogleEvents.Except(covertedList));
//var newList = googleEventList.Except(covertedList).Concat(covertedList.Except(googleEventList));
foreach (var ev in newList)
{
var restClientForAddingEvents = new RestClient();
var restRequestForAddingEvents = new RestRequest();
restClientForAddingEvents.BaseUrl = new System.Uri($"https://www.googleapis.com/calendar/v3/calendars/{credential.CalendarId}/events");
EventModel newEvent = new EventModel();
newEvent.Start.DateTime = DateTime.Parse(ev.Start.DateTime).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK");
newEvent.End.DateTime = DateTime.Parse(ev.End.DateTime).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK");
newEvent.Description = ev.Description;
newEvent.Id = Guid.NewGuid().ToString().Replace("-", "");
var model = JsonConvert.SerializeObject(newEvent, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
//Send parameters with the request
restRequest.AddQueryParameter("key", $"{ApiKeys}");
restRequest.AddHeader("Authorization", "Bearer " + accessToken);
restRequest.AddHeader("Accept", "application/json");
restRequest.AddHeader("Content-Type", "application/json; charset=utf-8");
restRequest.AddParameter("application/json", model, ParameterType.RequestBody);
//RestClient restClient = new RestClient(new Uri($"https://www.googleapis.com/calendar/v3/calendars/{calendarId}/events/" + ev.Id.ToString().Replace("-", "")));
//RestRequest restRequest = new RestRequest();
////Send parameters with the request
//restRequest.AddQueryParameter("key", $"{ApiKeys}");
//restRequest.AddHeader("Authorization", "Bearer " + accestoken);
//restRequest.AddHeader("Accept", "application/json");
try
{
//Post request to server
var restResponse = restClient.Post(restRequest);
//check if response is ok
if (restResponse.StatusCode == System.Net.HttpStatusCode.OK)
{
}
}
catch (Exception ex)
{
throw new Exception("Coulden't Create an event in google agenda.");
}
}
}
}
await Task.Delay(5000, stoppingToken);
}
}

RestSharp post request - Body with x-www-form-urlencoded values

I am using postman and making an api post request where I am adding body with x-www-form-urlencoded key/values and it works fine in postman.
The issue arrises when I try it from c# using RestSharp package.
I have tried the following code below but not getting the response. I get "BadRequest" invalid_client error.
public class ClientConfig {
public string client_id { get; set; } = "value here";
public string grant_type { get; set; } = "value here";
public string client_secret { get; set; } = "value here";
public string scope { get; set; } = "value here";
public string response_type { get; set; } = "value here";
}
public void GetResponse() {
var client = new RestClient("api-url-here");
var req = new RestRequest("endpoint-here",Method.POST);
var config = new ClientConfig();//values to pass in request
req.AddHeader("Content-Type","application/x-www-form-urlencoded");
req.AddParameter("application/x-www-form-urlencoded",config,ParameterType.RequestBody);
var res = client.Execute(req);
return;
}
//Also tried this
req.AddParameter("client_id",config.client_id,"application/x-www-form-urlencoded",ParameterType.RequestBody);
req.AddParameter("grant_type",config.grant_type,"application/x-www-form-urlencoded",ParameterType.RequestBody);
req.AddParameter("client_secret",config.client_secret,"application/x-www-form-urlencoded",ParameterType.RequestBody);
req.AddParameter("scope",config.scope,ParameterType.RequestBody);
req.AddParameter("response_type",config.response_type,"application/x-www-form-urlencoded",ParameterType.RequestBody);
//tried this too
var client = new RestClient("url-here");
var req = new RestRequest("endpointhere",Method.POST);
var config = new ClientConfig();
req.AddBody(config);
var res = client.Execute(req);
this working for me, it was generator from postman
var token = new TokenValidation()
{
app_id = CloudConfigurationManager.GetSetting("appId"),
secret = CloudConfigurationManager.GetSetting("secret"),
grant_type = CloudConfigurationManager.GetSetting("grant_type"),
Username = CloudConfigurationManager.GetSetting("Username"),
Password = CloudConfigurationManager.GetSetting("Password"),
};
var client = new RestClient($"{xxx}{tokenEndPoint}");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", $"app_id={token.app_id}&secret={token.secret}&grant_type={token.grant_type}&Username={token.Username}&Password={token.Password}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine("Access Token cannot obtain, process terminate");
return null;
}
var tokenResponse = JsonConvert.DeserializeObject<TokenValidationResponse>(response.Content);
I personally find this way to work better for me when sending Form-UrlEncoded data.
public void GetResponse() {
var client = new RestClient("api-url-here");
var req = new RestRequest("endpoint-here",Method.POST);
var config = new ClientConfig();//values to pass in request
// Content type is not required when adding parameters this way
// This will also automatically UrlEncode the values
req.AddParameter("client_id",config.client_id, ParameterType.GetOrPost);
req.AddParameter("grant_type",config.grant_type, ParameterType.GetOrPost);
req.AddParameter("client_secret",config.client_secret, ParameterType.GetOrPost);
req.AddParameter("scope",config.scope, ParameterType.GetOrPost);
req.AddParameter("response_type",config.response_type, ParameterType.GetOrPost);
var res = client.Execute(req);
return;
}
Details on this parameter type can be found here:
https://github.com/restsharp/RestSharp/wiki/ParameterTypes-for-RestRequest#getorpost
Personally, I found AddObject() method quite useful, and cleaner when you have so many parameters to add.
public void GetResponse() {
var client = new RestClient("api-url-here");
var req = new RestRequest("endpoint-here",Method.POST);
var config = new ClientConfig();//values to pass in request
req.AddHeader("Content-Type","application/x-www-form-urlencoded");
req.AddObject(config);
var res = client.Execute(req);
return res;
}
If it worked on postman, you can just press the code button on the right hand side. This will provide a working example in multiple languages. It is the button above the information icon. I would post a screenshot of it, but I don't have 10 reputation to do so.
i have found this good for my scenario , it is working perfect,
var client = new RestClient("https://test.salesforce.com/services/oauth2/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=password&client_id=3MVG9U_dUptXGpYKew7P.oPwrIsvowP_K4CsnkxHJIEOUJzW0XBUUY3o12bLDasjeIPGVobvBZo8TNFcCY6J3&client_secret=3189542819149073716&username=integraciones%40lamarina.com.mx.dev&password=2Password!4iwZvMQKVAwkYyJRy50JlAHk", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine("Response.StatusCode: " + response.StatusCode);
Console.WriteLine("Response.Content: " + response.Content);
Console.WriteLine("Response.ErrorMessage: " + response.ErrorMessage);
https://dotnetfiddle.net/J64FR5
in my case this is what worked
req.AddParameter("client_id", "unigen-corporation", ParameterType.HttpHeader);
req.AddParameter("grant_type", "client_credentials", ParameterType.GetOrPost);
If you've copied the code from the postman, try removing the following:
request.AlwaysMultipartFormData = true;
In my case after removing this line code worked.
var client1 = new RestClient(URI);
var request1 = new RestRequest(Method.POST);
request1.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request1.AddParameter("client_id", "XX");
request1.AddParameter("client_secret", "XX");
request1.AddParameter("grant_type", "XX");
request1.AddParameter("role", "XX");
IRestResponse response1 = client1.Execute(request1);
System.Console.WriteLine(response1.Content);
Add parameters according to your needs. This work fine!
for my code, this works perfect.
// extention function for object->formed data body string
public static string toFormDataBodyString(this object src)
{
var res = new List<string>();
foreach (var key in src.GetType().GetProperties())
{
res.Add($"{key.Name}={src.GetType().GetProperty(key.Name)?.GetValue(src)}");
}
return string.Join("&", res);
}
//--------------------------------------
var data = new {
param1 = xxxx,
param2 = xxxx
}
var translateReq = new RestRequest("url_here")
.AddHeader("Content-Type", "application/x-www-form-urlencoded")
.AddParameter("application/x-www-form-urlencoded", data.toFormDataBodyString(), ParameterType.RequestBody);

Getting people across projects

I am using the BCXAPI for .net and I am trying to get a list of people for a project but this doesn't seem to be available in the API.
I found documentation that shows it's possible:
GET /projects/#{project_id}/people.xml
but I was hoping not to have to break pattern and stick with using the api.
Can someone validate my suspicion that this can't be done with the BCXAPI?
I have been trying to piece together bits and pieces from different articels and I'm trying this approach:
var basecampProjects = s.GetProjects(a.Id);
foreach (var proj in basecampProjects)
{
var client = new RestClient()
{
BaseUrl = new Uri("https://basecamp.com/" + a.Id + "/api/v1/projects/" + proj.Id + "/people.json/")
};
client.Authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator(AccessToken.access_token);
var request = new RestRequest(Method.GET);
request.RequestFormat = DataFormat.Json;
request.AddHeader("User-Agent", "PicoDev (trevor#l9digitalstrategies.com)");
request.AddHeader("Content-type", "application/json");
request.AddHeader("charset", "utf - 8");
request.AddHeader("Authorization", AccessToken.access_token);
request.AddParameter("client_id", clientId);
request.AddParameter("client_secret", clientSecret);
var result = client.Execute(request);
string jsonResult = result.Content;
}
But I am getting a "not found" result. Is this not available anymore or am I just making a mistake in my call?
Ok so I found out that this is possible using the BCXAPI, here is how I implemented it api documentation here
var accounts = s.GetAccounts();
foreach (var a in accounts.accounts)
{
try
{
var basecampProjects = s.GetProjects(a.Id);
foreach (var proj in basecampProjects)
{
var accesses = s.GetAccessesForProject(a.Id, proj.Id);
}
}
catch (Exception ex)
{
}
}

How to POST request using RestSharp

I m trying to POST the request using RestSharp client as follows
I m passing the Auth Code to following function
public void ExchangeCodeForToken(string code)
{
if (string.IsNullOrEmpty(code))
{
OnAuthenticationFailed();
}
else
{
var request = new RestRequest(this.TokenEndPoint, Method.POST);
request.AddParameter("code", code);
request.AddParameter("client_id", this.ClientId);
request.AddParameter("client_secret", this.Secret);
request.AddParameter("redirect_uri", "urn:ietf:wg:oauth:2.0:oob");
request.AddParameter("grant_type", "authorization_code");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
client.ExecuteAsync<AuthResult>(request, GetAccessToken);
}
}
void GetAccessToken(IRestResponse<AuthResult> response)
{
if (response == null || response.StatusCode != HttpStatusCode.OK
|| response.Data == null
|| string.IsNullOrEmpty(response.Data.access_token))
{
OnAuthenticationFailed();
}
else
{
Debug.Assert(response.Data != null);
AuthResult = response.Data;
OnAuthenticated();
}
}
But i am getting response.StatusCode = Bad Request. Can anyone help me for how do i POST the request using Restsharp client.
My RestSharp POST method:
var client = new RestClient(ServiceUrl);
var request = new RestRequest("/resource/", Method.POST);
// Json to post.
string jsonToSend = JsonHelper.ToJson(json);
request.AddParameter("application/json; charset=utf-8", jsonToSend, ParameterType.RequestBody);
request.RequestFormat = DataFormat.Json;
try
{
client.ExecuteAsync(request, response =>
{
if (response.StatusCode == HttpStatusCode.OK)
{
// OK
}
else
{
// NOK
}
});
}
catch (Exception error)
{
// Log
}
This way works fine for me:
var request = new RestSharp.RestRequest("RESOURCE", RestSharp.Method.POST) { RequestFormat = RestSharp.DataFormat.Json }
.AddBody(BODY);
var response = Client.Execute(request);
// Handle response errors
HandleResponseErrors(response);
if (Errors.Length == 0)
{ }
else
{ }
Hope this helps! (Although it is a bit late)
As of 2017 I post to a rest service and getting the results from it like that:
var loginModel = new LoginModel();
loginModel.DatabaseName = "TestDB";
loginModel.UserGroupCode = "G1";
loginModel.UserName = "test1";
loginModel.Password = "123";
var client = new RestClient(BaseUrl);
var request = new RestRequest("/Connect?", Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddBody(loginModel);
var response = client.Execute(request);
var obj = JObject.Parse(response.Content);
LoginResult result = new LoginResult
{
Status = obj["Status"].ToString(),
Authority = response.ResponseUri.Authority,
SessionID = obj["SessionID"].ToString()
};
it is better to use json after post your resuest like below
var clien = new RestClient("https://smple.com/");
var request = new RestRequest("index", Method.POST);
request.AddHeader("Sign", signinstance);
request.AddJsonBody(JsonConvert.SerializeObject(yourclass));
var response = client.Execute<YourReturnclassSample>(request);
if (response.StatusCode == System.Net.HttpStatusCode.Created)
{
return Ok(response.Content);
}
I added this helper method to handle my POST requests that return an object I care about.
For REST purists, I know, POSTs should not return anything besides a status. However, I had a large collection of ids that was too big for a query string parameter.
Helper Method:
public TResponse Post<TResponse>(string relativeUri, object postBody) where TResponse : new()
{
//Note: Ideally the RestClient isn't created for each request.
var restClient = new RestClient("http://localhost:999");
var restRequest = new RestRequest(relativeUri, Method.POST)
{
RequestFormat = DataFormat.Json
};
restRequest.AddBody(postBody);
var result = restClient.Post<TResponse>(restRequest);
if (!result.IsSuccessful)
{
throw new HttpException($"Item not found: {result.ErrorMessage}");
}
return result.Data;
}
Usage:
public List<WhateverReturnType> GetFromApi()
{
var idsForLookup = new List<int> {1, 2, 3, 4, 5};
var relativeUri = "/api/idLookup";
var restResponse = Post<List<WhateverReturnType>>(relativeUri, idsForLookup);
return restResponse;
}
It's better to specify the Json data body.
var client = new RestClient("URL");
var request = new RestRequest("Resources",Method.POST);
request.RequestFormat = RestSharp.DataFormat.Json;
request.AddBody(new classname
{
id = value1;
Name = "";
});
var response = client.Execute(request);
Check statusCode from response.
Always ensure that status code should be OK.

Rest sharp be sure that the asynchronous method is finished

Currently working on a project with the cloud / azure and windows phone 7, I must make a call to service.
For me the convenience I use sharp rest but I am facing a problem;
I do not know when my appeal is complete.
public static bool CreateUser(User userToCreate)
{
if (CheckNetwork())
{
var client = new RestClient(Global.Url);
var request = new RestRequest("/user", Method.POST);
MemoryStream ms = new MemoryStream();
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(User));
ser.WriteObject(ms, userToCreate);
string json = JsonHelper.ToJson(userToCreate);
request.AddHeader("Content-type", "application/json; charset=utf-8");
request.AddParameter("application/json; charset=utf-8", json, ParameterType.RequestBody);
request.RequestFormat = DataFormat.Json;
try
{
object resp = null;
client.ExecuteAsync(request, response =>
{
if (response.ResponseStatus == ResponseStatus.Completed)
{
RestResponse resource = response;
string content = resource.Content;
resp = Convert.ToBoolean(JsonHelper.FromJson<string>(content));
}
});
return (bool)resp;
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
return false;
}
}
MessageBox.Show("You are not connect to the network!");
return false;
}
In this example, the method return first "resp" before making his call to service.
How can I be sure I do not exit this method before resp not been filled?
EventWaitHandle Wait = new AutoResetEvent(false);
client.ExecuteAsync(request, response =>
{
if (response.ResponseStatus == ResponseStatus.Completed)
{
RestResponse resource = response;
string content = resource.Content;
resp = Convert.ToBoolean(JsonHelper.FromJson<string>(content));
Wait.Set();
}
});
Wait.WaitOne();

Categories

Resources